From 865c96096227db330f1ccca3f3f4391f25930e54 Mon Sep 17 00:00:00 2001 From: Michael Neumann Date: Fri, 11 Dec 2009 22:59:21 +0100 Subject: [PATCH] HAMMER - Implement experimental volume removal A volume other than the root volume can be removed with: hammer volume-del device filesystem WARNING: Experimental! --- sbin/hammer/cmd_volume.c | 52 +++- sbin/hammer/hammer.8 | 13 + sbin/hammer/hammer.c | 5 + sbin/hammer/hammer.h | 1 + sys/vfs/hammer/hammer.h | 6 +- sys/vfs/hammer/hammer_blockmap.c | 11 + sys/vfs/hammer/hammer_ioctl.c | 10 +- sys/vfs/hammer/hammer_ioctl.h | 5 +- sys/vfs/hammer/hammer_vfsops.c | 2 + sys/vfs/hammer/hammer_volume.c | 444 ++++++++++++++++++++++--------- 10 files changed, 417 insertions(+), 132 deletions(-) diff --git a/sbin/hammer/cmd_volume.c b/sbin/hammer/cmd_volume.c index 1dbe2c4cd0..2e2846dd6d 100644 --- a/sbin/hammer/cmd_volume.c +++ b/sbin/hammer/cmd_volume.c @@ -37,13 +37,14 @@ * Volume operations: * * - volume-add: Add new volume to HAMMER filesystem + * - volume-del: Remove volume from HAMMER filesystem */ #include "hammer.h" #include +#include static uint64_t check_volume(const char *vol_name); -static void volume_add_usage(int exit_code); /* * volume-add @@ -51,14 +52,17 @@ static void volume_add_usage(int exit_code); void hammer_cmd_volume_add(char **av, int ac) { - struct hammer_ioc_volume_add ioc; + struct hammer_ioc_volume ioc; int fd; + if (ac != 2) { + fprintf(stderr, "hammer volume-add \n"); + exit(1); + } + char *device = av[0]; char *filesystem = av[1]; - if (ac != 2) - volume_add_usage(1); fd = open(filesystem, O_RDONLY); if (fd < 0) { fprintf(stderr, "hammer volume-add: unable to access %s: %s\n", @@ -84,12 +88,44 @@ hammer_cmd_volume_add(char **av, int ac) close(fd); } -static +/* + * volume-del + */ void -volume_add_usage(int exit_code) +hammer_cmd_volume_del(char **av, int ac) { - fprintf(stderr, "hammer volume-add \n"); - exit(exit_code); + struct hammer_ioc_volume ioc; + int fd; + + if (ac != 2) { + fprintf(stderr, "hammer volume-del \n"); + exit(1); + } + + + char *device = av[0]; + char *filesystem = av[1]; + + fd = open(filesystem, O_RDONLY); + if (fd < 0) { + fprintf(stderr, "hammer volume-add: unable to access %s: %s\n", + filesystem, strerror(errno)); + exit(1); + } + + /* + * volume-del ioctl + */ + bzero(&ioc, sizeof(ioc)); + strncpy(ioc.device_name, device, MAXPATHLEN); + + if (ioctl(fd, HAMMERIOC_DEL_VOLUME, &ioc) < 0) { + fprintf(stderr, "hammer volume-del ioctl: %s\n", + strerror(errno)); + exit(1); + } + + close(fd); } /* diff --git a/sbin/hammer/hammer.8 b/sbin/hammer/hammer.8 index 43edbb1847..733086bec8 100644 --- a/sbin/hammer/hammer.8 +++ b/sbin/hammer/hammer.8 @@ -505,6 +505,19 @@ colon-separated to .Pa /etc/fstab and .Xr mount_hammer 8 . +.\" ==== volume-del ==== +.It Cm volume-del Ar device Ar filesystem +This command will remove volume +.Ar device +from +.Ar filesystem . +.Pp +Remember that you have to remove +.Ar device +from the colon-separated list in +.Pa /etc/fstab +and +.Xr mount_hammer 8 . .\" ==== snapshot ==== .It Cm snapshot Oo Ar filesystem Oc Ar snapshot-dir .It Cm snapshot Ar filesystem Ar snapshot-dir Op Ar note diff --git a/sbin/hammer/hammer.c b/sbin/hammer/hammer.c index 994957bfe7..6ca44473fc 100644 --- a/sbin/hammer/hammer.c +++ b/sbin/hammer/hammer.c @@ -401,6 +401,10 @@ main(int ac, char **av) hammer_cmd_volume_add(av + 1, ac - 1); exit(0); } + if (strcmp(av[0], "volume-del") == 0) { + hammer_cmd_volume_del(av + 1, ac - 1); + exit(0); + } uuid_name_lookup(&Hammer_FSType, "DragonFly HAMMER", &status); if (status != uuid_s_ok) { @@ -526,6 +530,7 @@ usage(int exit_code) "hammer version \n" "hammer version-upgrade [force]\n" "hammer volume-add \n" + "hammer volume-del \n" ); fprintf(stderr, "\nHAMMER utility version 3+ commands:\n"); diff --git a/sbin/hammer/hammer.h b/sbin/hammer/hammer.h index 6a486a794a..01b847e3cd 100644 --- a/sbin/hammer/hammer.h +++ b/sbin/hammer/hammer.h @@ -111,6 +111,7 @@ void hammer_cmd_info(void); void hammer_cmd_get_version(char **av, int ac); void hammer_cmd_set_version(char **av, int ac); void hammer_cmd_volume_add(char **av, int ac); +void hammer_cmd_volume_del(char **av, int ac); void hammer_get_cycle(hammer_base_elm_t base, hammer_tid_t *tidp); void hammer_set_cycle(hammer_base_elm_t base, hammer_tid_t tid); diff --git a/sys/vfs/hammer/hammer.h b/sys/vfs/hammer/hammer.h index ad8288159d..1192b846fe 100644 --- a/sys/vfs/hammer/hammer.h +++ b/sys/vfs/hammer/hammer.h @@ -750,6 +750,8 @@ struct hammer_mount { int last_newrecords; int count_newrecords; + int volume_to_remove; /* volume that is currently being removed */ + int inode_reclaims; /* inodes pending reclaim by flusher */ int count_inodes; /* total number of inodes */ int count_iqueued; /* inodes queued to flusher */ @@ -1242,7 +1244,9 @@ int hammer_ioc_upgrade_pseudofs(hammer_transaction_t trans, hammer_inode_t ip, int hammer_ioc_wait_pseudofs(hammer_transaction_t trans, hammer_inode_t ip, struct hammer_ioc_pseudofs_rw *pfs); int hammer_ioc_volume_add(hammer_transaction_t trans, hammer_inode_t ip, - struct hammer_ioc_volume_add *ioc); + struct hammer_ioc_volume *ioc); +int hammer_ioc_volume_del(hammer_transaction_t trans, hammer_inode_t ip, + struct hammer_ioc_volume *ioc); int hammer_signal_check(hammer_mount_t hmp); diff --git a/sys/vfs/hammer/hammer_blockmap.c b/sys/vfs/hammer/hammer_blockmap.c index ef77d72af8..bff567f92c 100644 --- a/sys/vfs/hammer/hammer_blockmap.c +++ b/sys/vfs/hammer/hammer_blockmap.c @@ -164,6 +164,17 @@ again: */ layer1_offset = freemap->phys_offset + HAMMER_BLOCKMAP_LAYER1_OFFSET(next_offset); + + /* + * Skip this block if it is belonging to a volume that we are + * currently trying to remove from the file-system. + */ + if ((int)HAMMER_VOL_DECODE(layer1_offset) == hmp->volume_to_remove) { + next_offset = (next_offset + HAMMER_BLOCKMAP_LAYER2) & + ~HAMMER_BLOCKMAP_LAYER2_MASK; + goto again; + } + layer1 = hammer_bread(hmp, layer1_offset, errorp, &buffer1); if (*errorp) { result_offset = 0; diff --git a/sys/vfs/hammer/hammer_ioctl.c b/sys/vfs/hammer/hammer_ioctl.c index 3e9660c4cc..2e039f0c01 100644 --- a/sys/vfs/hammer/hammer_ioctl.c +++ b/sys/vfs/hammer/hammer_ioctl.c @@ -162,7 +162,15 @@ hammer_ioctl(hammer_inode_t ip, u_long com, caddr_t data, int fflag, error = priv_check_cred(cred, PRIV_HAMMER_VOLUME, 0); if (error == 0) error = hammer_ioc_volume_add(&trans, ip, - (struct hammer_ioc_volume_add *)data); + (struct hammer_ioc_volume *)data); + } + break; + case HAMMERIOC_DEL_VOLUME: + if (error == 0) { + error = priv_check_cred(cred, PRIV_HAMMER_VOLUME, 0); + if (error == 0) + error = hammer_ioc_volume_del(&trans, ip, + (struct hammer_ioc_volume *)data); } break; case HAMMERIOC_ADD_SNAPSHOT: diff --git a/sys/vfs/hammer/hammer_ioctl.h b/sys/vfs/hammer/hammer_ioctl.h index 951c9252d5..ace6fef269 100644 --- a/sys/vfs/hammer/hammer_ioctl.h +++ b/sys/vfs/hammer/hammer_ioctl.h @@ -335,7 +335,7 @@ struct hammer_ioc_version { char description[64]; }; -struct hammer_ioc_volume_add { +struct hammer_ioc_volume { struct hammer_ioc_head head; char device_name[MAXPATHLEN]; int64_t vol_size; @@ -451,12 +451,13 @@ struct hammer_ioc_config { #define HAMMERIOC_SET_VERSION _IOWR('h',14,struct hammer_ioc_version) #define HAMMERIOC_REBALANCE _IOWR('h',15,struct hammer_ioc_rebalance) #define HAMMERIOC_GET_INFO _IOR('h',16,struct hammer_ioc_info) -#define HAMMERIOC_ADD_VOLUME _IOWR('h',17,struct hammer_ioc_volume_add) +#define HAMMERIOC_ADD_VOLUME _IOWR('h',17,struct hammer_ioc_volume) #define HAMMERIOC_ADD_SNAPSHOT _IOWR('h',18,struct hammer_ioc_snapshot) #define HAMMERIOC_DEL_SNAPSHOT _IOWR('h',19,struct hammer_ioc_snapshot) #define HAMMERIOC_GET_SNAPSHOT _IOWR('h',20,struct hammer_ioc_snapshot) #define HAMMERIOC_GET_CONFIG _IOWR('h',21,struct hammer_ioc_config) #define HAMMERIOC_SET_CONFIG _IOWR('h',22,struct hammer_ioc_config) +#define HAMMERIOC_DEL_VOLUME _IOWR('h',24,struct hammer_ioc_volume) #endif diff --git a/sys/vfs/hammer/hammer_vfsops.c b/sys/vfs/hammer/hammer_vfsops.c index 674ec2ee8b..c78c33e7d5 100644 --- a/sys/vfs/hammer/hammer_vfsops.c +++ b/sys/vfs/hammer/hammer_vfsops.c @@ -434,6 +434,8 @@ hammer_vfs_mount(struct mount *mp, char *mntpt, caddr_t data, hmp->asof = HAMMER_MAX_TID; } + hmp->volume_to_remove = -1; + /* * Re-open read-write if originally read-only, or vise-versa. * diff --git a/sys/vfs/hammer/hammer_volume.c b/sys/vfs/hammer/hammer_volume.c index 50af62c3e8..ff6b64fbf7 100644 --- a/sys/vfs/hammer/hammer_volume.c +++ b/sys/vfs/hammer/hammer_volume.c @@ -51,35 +51,19 @@ hammer_format_volume_header(struct hammer_mount *hmp, struct vnode *devvp, int64_t vol_size, int64_t boot_area_size, int64_t mem_area_size); static uint64_t -hammer_format_freemap(struct hammer_mount *hmp, - hammer_transaction_t trans, - hammer_volume_t volume); +hammer_format_freemap(hammer_transaction_t trans, hammer_volume_t volume); -static uint64_t -hammer_format_layer2_chunk(struct hammer_mount *hmp, - hammer_transaction_t trans, - hammer_off_t phys_offset, - hammer_off_t aligned_buf_end_off, - hammer_buffer_t *bufferp, - int *errorp); +static int +hammer_free_freemap(hammer_transaction_t trans, hammer_volume_t volume); -static void -hammer_set_layer1_entry(struct hammer_mount *hmp, - hammer_transaction_t trans, - hammer_off_t phys_offset, - uint64_t free_bigblocks, - hammer_blockmap_t freemap, - hammer_buffer_t *bufferp, - int *errorp); int hammer_ioc_volume_add(hammer_transaction_t trans, hammer_inode_t ip, - struct hammer_ioc_volume_add *ioc) + struct hammer_ioc_volume *ioc) { struct hammer_mount *hmp = trans->hmp; struct mount *mp = hmp->mp; hammer_volume_t volume; - hammer_volume_t root_volume; int error; if (mp->mnt_flag & MNT_RDONLY) { @@ -156,32 +140,29 @@ hammer_ioc_volume_add(hammer_transaction_t trans, hammer_inode_t ip, volume = hammer_get_volume(hmp, free_vol_no, &error); KKASSERT(volume != NULL && error == 0); - root_volume = hammer_get_root_volume(hmp, &error); - KKASSERT(root_volume != NULL && error == 0); uint64_t total_free_bigblocks = - hammer_format_freemap(hmp, trans, volume); + hammer_format_freemap(trans, volume); /* * Increase the total number of bigblocks */ - hammer_modify_volume_field(trans, root_volume, + hammer_modify_volume_field(trans, trans->rootvol, vol0_stat_bigblocks); - root_volume->ondisk->vol0_stat_bigblocks += total_free_bigblocks; - hammer_modify_volume_done(root_volume); + trans->rootvol->ondisk->vol0_stat_bigblocks += total_free_bigblocks; + hammer_modify_volume_done(trans->rootvol); /* * Increase the number of free bigblocks * (including the copy in hmp) */ - hammer_modify_volume_field(trans, root_volume, + hammer_modify_volume_field(trans, trans->rootvol, vol0_stat_freebigblocks); - root_volume->ondisk->vol0_stat_freebigblocks += total_free_bigblocks; + trans->rootvol->ondisk->vol0_stat_freebigblocks += total_free_bigblocks; hmp->copy_stat_freebigblocks = - root_volume->ondisk->vol0_stat_freebigblocks; - hammer_modify_volume_done(root_volume); + trans->rootvol->ondisk->vol0_stat_freebigblocks; + hammer_modify_volume_done(trans->rootvol); - hammer_rel_volume(root_volume, 0); hammer_rel_volume(volume, 0); hammer_unlock(&hmp->blkmap_lock); @@ -193,151 +174,374 @@ end: return (error); } -static uint64_t -hammer_format_freemap(struct hammer_mount *hmp, - hammer_transaction_t trans, - hammer_volume_t volume) + +/* + * Remove a volume. + */ +int +hammer_ioc_volume_del(hammer_transaction_t trans, hammer_inode_t ip, + struct hammer_ioc_volume *ioc) { - hammer_off_t phys_offset; + struct hammer_mount *hmp = trans->hmp; + struct mount *mp = hmp->mp; + hammer_volume_t volume; + int error = 0; + + if (mp->mnt_flag & MNT_RDONLY) { + kprintf("Cannot del volume from read-only HAMMER filesystem\n"); + return (EINVAL); + } + + + volume = NULL; + + /* + * find volume by volname + */ + for (int vol_no = 0; vol_no < HAMMER_MAX_VOLUMES; ++vol_no) { + volume = hammer_get_volume(hmp, vol_no, &error); + if (volume == NULL && error == ENOENT) { + /* + * Skip unused volume numbers + */ + error = 0; + continue; + } + KKASSERT(volume != NULL && error == 0); + if (strcmp(volume->vol_name, ioc->device_name) == 0) { + break; + } + volume = NULL; + } + + if (!volume) { + kprintf("Couldn't find volume\n"); + return (EINVAL); + } + + if (volume == trans->rootvol) { + kprintf("Cannot remove root-volume\n"); + hammer_rel_volume(volume, 0); + return (EINVAL); + } + + /* + * + */ + + hmp->volume_to_remove = volume->vol_no; + + struct hammer_ioc_reblock reblock; + bzero(&reblock, sizeof(reblock)); + + reblock.key_beg.localization = HAMMER_MIN_LOCALIZATION; + reblock.key_beg.obj_id = HAMMER_MIN_OBJID; + reblock.key_end.localization = HAMMER_MAX_LOCALIZATION; + reblock.key_end.obj_id = HAMMER_MAX_OBJID; + //reblock.head.flags = flags & HAMMER_IOC_DO_FLAGS; + reblock.free_level = HAMMER_LARGEBLOCK_SIZE; + reblock.free_level = 0; + + error = hammer_ioc_reblock(trans, ip, &reblock); + + if (error) { + kprintf("reblock failed: %d\n", error); + hmp->volume_to_remove = -1; + hammer_rel_volume(volume, 0); + return (error); + } + + hammer_sync_lock_sh(trans); + hammer_lock_ex(&hmp->blkmap_lock); + + error = hammer_free_freemap(trans, volume); + if (error) { + kprintf("Failed to free volume\n"); + hmp->volume_to_remove = -1; + hammer_rel_volume(volume, 0); + hammer_unlock(&hmp->blkmap_lock); + hammer_sync_unlock(trans); + return (error); + } + + hmp->volume_to_remove = -1; + hammer_rel_volume(volume, 1); + + /* XXX: unload volume! */ + /*error = hammer_unload_volume(volume, NULL); + if (error == -1) { + kprintf("Failed to unload volume\n"); + hammer_unlock(&hmp->blkmap_lock); + hammer_sync_unlock(trans); + return (error); + }*/ + + --hmp->nvolumes; + + /* + * Set each volume's new value of the vol_count field. + */ + for (int vol_no = 0; vol_no < HAMMER_MAX_VOLUMES; ++vol_no) { + volume = hammer_get_volume(hmp, vol_no, &error); + if (volume == NULL && error == ENOENT) { + /* + * Skip unused volume numbers + */ + error = 0; + continue; + } + KKASSERT(volume != NULL && error == 0); + hammer_modify_volume_field(trans, volume, vol_count); + volume->ondisk->vol_count = hmp->nvolumes; + hammer_modify_volume_done(volume); + hammer_rel_volume(volume, 0); + } + + hammer_unlock(&hmp->blkmap_lock); + hammer_sync_unlock(trans); + + return (0); +} + + +/* + * Iterate over all usable L1 entries of the volume and + * the corresponding L2 entries. + */ +static int +hammer_iterate_l1l2_entries(hammer_transaction_t trans, hammer_volume_t volume, + int (*callback)(hammer_transaction_t, hammer_buffer_t *, + struct hammer_blockmap_layer1*, struct hammer_blockmap_layer2 *, + hammer_off_t, int, void *), + void *data) +{ + struct hammer_mount *hmp = trans->hmp; + hammer_blockmap_t freemap = &hmp->blockmap[HAMMER_ZONE_FREEMAP_INDEX]; hammer_buffer_t buffer = NULL; - hammer_blockmap_t freemap; - hammer_off_t aligned_buf_end_off; - uint64_t free_bigblocks; - uint64_t total_free_bigblocks; int error = 0; - total_free_bigblocks = 0; + hammer_off_t phys_off; + hammer_off_t block_off; + hammer_off_t layer1_off; + hammer_off_t layer2_off; + hammer_off_t aligned_buf_end_off; + struct hammer_blockmap_layer1 *layer1; + struct hammer_blockmap_layer2 *layer2; /* - * Calculate the usable size of the new volume, which + * Calculate the usable size of the volume, which * must be aligned at a bigblock (8 MB) boundary. */ - aligned_buf_end_off = HAMMER_ENCODE_RAW_BUFFER(volume->ondisk->vol_no, + aligned_buf_end_off = (HAMMER_ENCODE_RAW_BUFFER(volume->ondisk->vol_no, (volume->ondisk->vol_buf_end - volume->ondisk->vol_buf_beg) - & ~HAMMER_LARGEBLOCK_MASK64); - - freemap = &hmp->blockmap[HAMMER_ZONE_FREEMAP_INDEX]; + & ~HAMMER_LARGEBLOCK_MASK64)); /* - * Iterate the volume's address space in chunks of 4 TB, - * where each chunk consists of at least one physically - * available 8 MB bigblock. + * Iterate the volume's address space in chunks of 4 TB, where each + * chunk consists of at least one physically available 8 MB bigblock. * * For each chunk we need one L1 entry and one L2 bigblock. * We use the first bigblock of each chunk as L2 block. */ - for (phys_offset = HAMMER_ENCODE_RAW_BUFFER(volume->ondisk->vol_no, 0); - phys_offset < aligned_buf_end_off; - phys_offset += HAMMER_BLOCKMAP_LAYER2) { - - free_bigblocks = hammer_format_layer2_chunk(hmp, trans, - phys_offset, aligned_buf_end_off, &buffer, &error); - KKASSERT(error == 0); + for (phys_off = HAMMER_ENCODE_RAW_BUFFER(volume->ondisk->vol_no, 0); + phys_off < aligned_buf_end_off; + phys_off += HAMMER_BLOCKMAP_LAYER2) { + for (block_off = 0; + block_off < HAMMER_BLOCKMAP_LAYER2; + block_off += HAMMER_LARGEBLOCK_SIZE) { + layer2_off = phys_off + + HAMMER_BLOCKMAP_LAYER2_OFFSET(block_off); + layer2 = hammer_bread(hmp, layer2_off, &error, + &buffer); + if (error) + goto end; + + int zone; + if (block_off == 0) { + /* + * The first entry represents the L2 bigblock + * itself. + */ + zone = HAMMER_ZONE_FREEMAP_INDEX; + } else if (phys_off + block_off < aligned_buf_end_off) { + /* + * Available bigblock + */ + zone = 0; + } else { + /* + * Bigblock outside of physically available + * space + */ + zone = HAMMER_ZONE_UNAVAIL_INDEX; + } + + error = callback(trans, &buffer, NULL, layer2, 0, zone, + data); + if (error) + goto end; + } - hammer_set_layer1_entry(hmp, trans, phys_offset, - free_bigblocks, freemap, &buffer, &error); - KKASSERT(error == 0); + layer1_off = freemap->phys_offset + + HAMMER_BLOCKMAP_LAYER1_OFFSET(phys_off); + layer1 = hammer_bread(hmp, layer1_off, &error, &buffer); + if (error) + goto end; - total_free_bigblocks += free_bigblocks; + error = callback(trans, &buffer, layer1, NULL, phys_off, 0, + data); + if (error) + goto end; } +end: if (buffer) { hammer_rel_buffer(buffer, 0); buffer = NULL; } - return total_free_bigblocks; + return error; } -/* - * Format the L2 bigblock representing a 4 TB chunk. - * - * Returns the number of free bigblocks. - */ -static uint64_t -hammer_format_layer2_chunk(struct hammer_mount *hmp, - hammer_transaction_t trans, - hammer_off_t phys_offset, - hammer_off_t aligned_buf_end_off, - hammer_buffer_t *bufferp, - int *errorp) +struct format_bigblock_stat { + uint64_t total_free_bigblocks; + uint64_t free_bigblocks; +}; + +static int +format_callback(hammer_transaction_t trans, hammer_buffer_t *bufferp, + struct hammer_blockmap_layer1 *layer1, + struct hammer_blockmap_layer2 *layer2, + hammer_off_t phys_off, + int layer2_zone, + void *data) { - uint64_t free_bigblocks = 0; - hammer_off_t block_off; - hammer_off_t layer2_offset; - struct hammer_blockmap_layer2 *layer2; + struct format_bigblock_stat *stat = (struct format_bigblock_stat*)data; - for (block_off = 0; - block_off < HAMMER_BLOCKMAP_LAYER2; - block_off += HAMMER_LARGEBLOCK_SIZE) { - layer2_offset = phys_offset + - HAMMER_BLOCKMAP_LAYER2_OFFSET(block_off); - layer2 = hammer_bread(hmp, layer2_offset, errorp, bufferp); - if (*errorp) - return free_bigblocks; + if (layer1) { + KKASSERT(layer1->phys_offset == HAMMER_BLOCKMAP_UNAVAIL); - KKASSERT(layer2); + hammer_modify_buffer(trans, *bufferp, layer1, sizeof(*layer1)); + bzero(layer1, sizeof(layer1)); + layer1->phys_offset = phys_off; + layer1->blocks_free = stat->free_bigblocks; + layer1->layer1_crc = crc32(layer1, HAMMER_LAYER1_CRCSIZE); + hammer_modify_buffer_done(*bufferp); + stat->total_free_bigblocks += stat->free_bigblocks; + stat->free_bigblocks = 0; /* reset */ + } else if (layer2) { hammer_modify_buffer(trans, *bufferp, layer2, sizeof(*layer2)); bzero(layer2, sizeof(*layer2)); - if (block_off == 0) { + layer2->zone = layer2_zone; + + switch (layer2->zone) { + case HAMMER_ZONE_FREEMAP_INDEX: /* * The first entry represents the L2 bigblock itself. */ - layer2->zone = HAMMER_ZONE_FREEMAP_INDEX; layer2->append_off = HAMMER_LARGEBLOCK_SIZE; layer2->bytes_free = 0; - } else if (phys_offset + block_off < aligned_buf_end_off) { - layer2->zone = 0; + break; + + case 0: + /* + * Available bigblock + */ layer2->append_off = 0; layer2->bytes_free = HAMMER_LARGEBLOCK_SIZE; - ++free_bigblocks; - } else { + ++stat->free_bigblocks; + break; + + case HAMMER_ZONE_UNAVAIL_INDEX: /* * Bigblock outside of physically available space */ - layer2->zone = HAMMER_ZONE_UNAVAIL_INDEX; layer2->append_off = HAMMER_LARGEBLOCK_SIZE; layer2->bytes_free = 0; + break; + default: + KKASSERT(0); } + layer2->entry_crc = crc32(layer2, HAMMER_LAYER2_CRCSIZE); + hammer_modify_buffer_done(*bufferp); + } else { + KKASSERT(0); + } + + return 0; +} +static uint64_t +hammer_format_freemap(hammer_transaction_t trans, hammer_volume_t volume) +{ + int error = 0; + + struct format_bigblock_stat stat; + stat.total_free_bigblocks = 0; + stat.free_bigblocks = 0; + + error = hammer_iterate_l1l2_entries(trans, volume, format_callback, + (void*)&stat); + KKASSERT(error == 0); + + return stat.total_free_bigblocks; +} + +static int +free_callback(hammer_transaction_t trans, hammer_buffer_t *bufferp, + struct hammer_blockmap_layer1 *layer1, + struct hammer_blockmap_layer2 *layer2, + hammer_off_t phys_off, + int layer2_zone, + void *data __unused) +{ + if (layer1) { + /* + * Free the L1 entry + */ + hammer_modify_buffer(trans, *bufferp, layer1, sizeof(*layer1)); + bzero(layer1, sizeof(layer1)); + layer1->phys_offset = HAMMER_BLOCKMAP_UNAVAIL; + layer1->layer1_crc = crc32(layer1, HAMMER_LAYER1_CRCSIZE); hammer_modify_buffer_done(*bufferp); + + return 0; + } else if (layer2) { + switch (layer2_zone) { + case HAMMER_ZONE_FREEMAP_INDEX: + case HAMMER_ZONE_UNAVAIL_INDEX: + return 0; + case 0: + if (layer2->append_off == 0 && + layer2->bytes_free == HAMMER_LARGEBLOCK_SIZE) { + return 0; + } else { + return EINVAL; /* FIXME */ + } + default: + return EINVAL; /* FIXME */ + } + } else { + KKASSERT(0); } - return free_bigblocks; + return EINVAL; } -static void -hammer_set_layer1_entry(struct hammer_mount *hmp, - hammer_transaction_t trans, - hammer_off_t phys_offset, - uint64_t free_bigblocks, - hammer_blockmap_t freemap, - hammer_buffer_t *bufferp, - int *errorp) +static int +hammer_free_freemap(hammer_transaction_t trans, hammer_volume_t volume) { - struct hammer_blockmap_layer1 *layer1; - hammer_off_t layer1_offset; - - layer1_offset = freemap->phys_offset + - HAMMER_BLOCKMAP_LAYER1_OFFSET(phys_offset); - layer1 = hammer_bread(hmp, layer1_offset, errorp, bufferp); - if (*errorp) - return; - KKASSERT(layer1); - KKASSERT(layer1->phys_offset == HAMMER_BLOCKMAP_UNAVAIL); - - hammer_modify_buffer(trans, *bufferp, layer1, sizeof(*layer1)); - bzero(layer1, sizeof(*layer1)); - layer1->phys_offset = phys_offset; - layer1->blocks_free = free_bigblocks; - layer1->layer1_crc = crc32(layer1, HAMMER_LAYER1_CRCSIZE); - - hammer_modify_buffer_done(*bufferp); + return hammer_iterate_l1l2_entries(trans, volume, free_callback, NULL); } +/************************************************************************ + * MISC * + ************************************************************************ + */ + static int hammer_setup_device(struct vnode **devvpp, const char *dev_path, int ronly) { -- 2.41.0