From: Michael Neumann Date: Tue, 14 Jul 2009 14:01:40 +0000 (+0200) Subject: Merge branch 'master' of ssh://crater.dragonflybsd.org/repository/git/dragonfly X-Git-Tag: v2.4.0~445^2~4 X-Git-Url: https://gitweb.dragonflybsd.org/dragonfly.git/commitdiff_plain/5aaa1b10c24e15ae1a3701e3f7654aeeb8bf8305?hp=1a0c098848e37b01d9cb5f0e151e31cad8c72e2f Merge branch 'master' of ssh://crater.dragonflybsd.org/repository/git/dragonfly --- diff --git a/sbin/hammer/Makefile b/sbin/hammer/Makefile index 9900c4154e..32ae468d13 100644 --- a/sbin/hammer/Makefile +++ b/sbin/hammer/Makefile @@ -7,7 +7,7 @@ SRCS= hammer.c ondisk.c blockmap.c cache.c misc.c cycle.c \ cmd_blockmap.c cmd_reblock.c cmd_rebalance.c \ cmd_synctid.c cmd_stats.c \ cmd_pseudofs.c cmd_snapshot.c cmd_mirror.c cmd_status.c \ - cmd_cleanup.c cmd_info.c cmd_version.c + cmd_cleanup.c cmd_info.c cmd_version.c cmd_expand.c MAN= hammer.8 CFLAGS+= -I${.CURDIR}/../../sys -DALIST_NO_DEBUG diff --git a/sbin/hammer/cmd_expand.c b/sbin/hammer/cmd_expand.c new file mode 100644 index 0000000000..4da637ed65 --- /dev/null +++ b/sbin/hammer/cmd_expand.c @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2009 The DragonFly Project. All rights reserved. + * + * This code is derived from software contributed to The DragonFly Project + * by Matthew Dillon and + * Michael Neumann + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of The DragonFly Project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific, prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ +/* + * Expand a HAMMER filesystem. + */ + +#include "hammer.h" +#include + +static uint64_t check_volume(const char *vol_name); +static void expand_usage(int exit_code); + +/* + * expand + */ +void +hammer_cmd_expand(char **av, int ac) +{ + struct hammer_ioc_expand expand; + int fd; + + if (ac != 2) + expand_usage(1); + fd = open(av[0], O_RDONLY); + if (fd < 0) { + fprintf(stderr, "hammer expand: unable to access %s: %s\n", + av[0], strerror(errno)); + exit(1); + } + + bzero(&expand, sizeof(expand)); + strncpy(expand.device_name, av[1], MAXPATHLEN); + expand.vol_size = check_volume(av[1]); + expand.boot_area_size = 0; // XXX + expand.mem_area_size = 0; // XXX + + if (ioctl(fd, HAMMERIOC_EXPAND, &expand) < 0) { + fprintf(stderr, "hammer expand ioctl: %s\n", strerror(errno)); + exit(1); + } + + close(fd); +} + +static +void +expand_usage(int exit_code) +{ + fprintf(stderr, "hammer expand \n"); + exit(exit_code); +} + +/* + * Check basic volume characteristics. HAMMER filesystems use a minimum + * of a 16KB filesystem buffer size. + * + * Returns the size of the device. + * + * From newfs_hammer.c + */ +static +uint64_t +check_volume(const char *vol_name) +{ + struct partinfo pinfo; + int fd; + + /* + * Get basic information about the volume + */ + fd = open(vol_name, O_RDWR); + if (fd < 0) + errx(1, "Unable to open %s R+W", vol_name); + + if (ioctl(fd, DIOCGPART, &pinfo) < 0) { + errx(1, "No block device: %s", vol_name); + } + /* + * When formatting a block device as a HAMMER volume the + * sector size must be compatible. HAMMER uses 16384 byte + * filesystem buffers. + */ + if (pinfo.reserved_blocks) { + errx(1, "HAMMER cannot be placed in a partition " + "which overlaps the disklabel or MBR"); + } + if (pinfo.media_blksize > 16384 || + 16384 % pinfo.media_blksize) { + errx(1, "A media sector size of %d is not supported", + pinfo.media_blksize); + } + + close(fd); + return pinfo.media_size; +} diff --git a/sbin/hammer/hammer.c b/sbin/hammer/hammer.c index 18e3333fcc..17eb81a361 100644 --- a/sbin/hammer/hammer.c +++ b/sbin/hammer/hammer.c @@ -356,6 +356,10 @@ main(int ac, char **av) hammer_cmd_set_version(av + 1, ac - 1); exit(0); } + if (strcmp(av[0], "expand") == 0) { + hammer_cmd_expand(av + 1, ac - 1); + exit(0); + } uuid_name_lookup(&Hammer_FSType, "DragonFly HAMMER", &status); if (status != uuid_s_ok) { @@ -463,6 +467,7 @@ usage(int exit_code) " [[user@]host:]\n" "hammer version \n" "hammer version-upgrade version# [force]\n" + "hammer expand \n" ); exit(exit_code); } diff --git a/sbin/hammer/hammer.h b/sbin/hammer/hammer.h index 4d05a1c684..d055888534 100644 --- a/sbin/hammer/hammer.h +++ b/sbin/hammer/hammer.h @@ -100,6 +100,7 @@ void hammer_cmd_cleanup(char **av, int ac); void hammer_cmd_info(int ac); void hammer_cmd_get_version(char **av, int ac); void hammer_cmd_set_version(char **av, int ac); +void hammer_cmd_expand(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/conf/files b/sys/conf/files index 4e431a2192..459cd516d0 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -1382,6 +1382,7 @@ vfs/userfs/userfs_elms.c optional userfs vfs/hammer/hammer_blockmap.c optional hammer vfs/hammer/hammer_btree.c optional hammer vfs/hammer/hammer_cursor.c optional hammer +vfs/hammer/hammer_expand.c optional hammer vfs/hammer/hammer_flusher.c optional hammer vfs/hammer/hammer_freemap.c optional hammer vfs/hammer/hammer_inode.c optional hammer diff --git a/sys/vfs/hammer/Makefile b/sys/vfs/hammer/Makefile index b687619734..f40e0dcd1b 100644 --- a/sys/vfs/hammer/Makefile +++ b/sys/vfs/hammer/Makefile @@ -9,7 +9,7 @@ SRCS= hammer_vfsops.c hammer_vnops.c hammer_inode.c \ hammer_blockmap.c hammer_freemap.c hammer_undo.c \ hammer_reblock.c hammer_rebalance.c \ hammer_flusher.c hammer_mirror.c \ - hammer_pfs.c hammer_prune.c + hammer_pfs.c hammer_prune.c hammer_expand.c SRCS+= opt_ktr.h .include diff --git a/sys/vfs/hammer/hammer.h b/sys/vfs/hammer/hammer.h index 2696acc3ac..d0c7952237 100644 --- a/sys/vfs/hammer/hammer.h +++ b/sys/vfs/hammer/hammer.h @@ -1218,6 +1218,8 @@ int hammer_ioc_upgrade_pseudofs(hammer_transaction_t trans, hammer_inode_t ip, struct hammer_ioc_pseudofs_rw *pfs); int hammer_ioc_wait_pseudofs(hammer_transaction_t trans, hammer_inode_t ip, struct hammer_ioc_pseudofs_rw *pfs); +int hammer_ioc_expand(hammer_transaction_t trans, hammer_inode_t ip, + struct hammer_ioc_expand *expand); int hammer_signal_check(hammer_mount_t hmp); diff --git a/sys/vfs/hammer/hammer_expand.c b/sys/vfs/hammer/hammer_expand.c new file mode 100644 index 0000000000..0d21f85fe5 --- /dev/null +++ b/sys/vfs/hammer/hammer_expand.c @@ -0,0 +1,227 @@ +/* + * Copyright (c) 2009 The DragonFly Project. All rights reserved. + * + * This code is derived from software contributed to The DragonFly Project + * by Matthew Dillon and + * Michael Neumann + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of The DragonFly Project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific, prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include "hammer.h" +#include +#include +#include + +static int +hammer_format_volume_header(struct hammer_mount *hmp, const char *vol_name, + int vol_no, int vol_count, + int64_t vol_size, int64_t boot_area_size, int64_t mem_area_size); + + +int +hammer_ioc_expand(hammer_transaction_t trans, hammer_inode_t ip, + struct hammer_ioc_expand *expand) +{ + struct hammer_mount *hmp = trans->hmp; + struct mount *mp = hmp->mp; + int error; + + if (mp->mnt_flag & MNT_RDONLY) { + kprintf("Cannot expand read-only HAMMER filesystem\n"); + return (EINVAL); + } + + if (hmp->nvolumes + 1 >= HAMMER_MAX_VOLUMES) { + kprintf("Max number of HAMMER volumes exceeded\n"); + return (EINVAL); + } + + error = hammer_format_volume_header( + hmp, + hmp->rootvol->ondisk->vol_name, + hmp->nvolumes, + hmp->nvolumes+1, + expand->vol_size, + expand->boot_area_size, + expand->mem_area_size); + + if (error == 0) { + error = hammer_install_volume(hmp, expand->device_name, NULL); + } + + if (error == 0) { + ++hmp->nvolumes; + hammer_sync_lock_sh(trans); + hammer_lock_ex(&hmp->blkmap_lock); + + /* + * Set each volumes new value of the vol_count field. + */ + for (int vol_no = 0; vol_no < hmp->nvolumes; ++vol_no) { + hammer_volume_t volume; + volume = hammer_get_volume(hmp, vol_no, &error); + KKASSERT(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); + } + + if (error) { + kprintf("An error occured: %d\n", error); + } + + return (error); +} + +static int +hammer_format_volume_header(struct hammer_mount *hmp, const char *vol_name, + int vol_no, int vol_count, + int64_t vol_size, int64_t boot_area_size, int64_t mem_area_size) +{ + struct vnode *devvp = NULL; + struct buf *bp = NULL; + struct nlookupdata nd; + struct hammer_volume_ondisk *ondisk; + int error; + + /* + * Get the device vnode + */ + error = nlookup_init(&nd, vol_name, UIO_SYSSPACE, NLC_FOLLOW); + if (error == 0) + error = nlookup(&nd); + if (error == 0) + error = cache_vref(&nd.nl_nch, nd.nl_cred, &devvp); + nlookup_done(&nd); + + if (error == 0) { + if (vn_isdisk(devvp, &error)) { + error = vfs_mountedon(devvp); + } + } + if (error == 0 && + count_udev(devvp->v_umajor, devvp->v_uminor) > 0) { + error = EBUSY; + } + if (error == 0) { + vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); + error = vinvalbuf(devvp, V_SAVE, 0, 0); + if (error == 0) { + error = VOP_OPEN(devvp, FREAD|FWRITE, FSCRED, NULL); + } + vn_unlock(devvp); + } + if (error) { + if (devvp) + vrele(devvp); + return (error); + } + + /* + * Extract the volume number from the volume header and do various + * sanity checks. + */ + KKASSERT(HAMMER_BUFSIZE >= sizeof(struct hammer_volume_ondisk)); + error = bread(devvp, 0LL, HAMMER_BUFSIZE, &bp); + if (error || bp->b_bcount < sizeof(struct hammer_volume_ondisk)) + goto late_failure; + + ondisk = (struct hammer_volume_ondisk*) bp->b_data; + + /* + * Note that we do NOT allow to use a device that contains + * a valid HAMMER signature. It has to be cleaned up with dd + * before. + */ + if (ondisk->vol_signature == HAMMER_FSBUF_VOLUME) { + kprintf("hammer_expand: Formatting of valid HAMMER volume " + "%s denied. Erase with dd!\n", vol_name); + error = EFTYPE; + goto late_failure; + } + + bzero(ondisk, sizeof(struct hammer_volume_ondisk)); + ksnprintf(ondisk->vol_name, sizeof(ondisk->vol_name), "%s", vol_name); + ondisk->vol_fstype = hmp->rootvol->ondisk->vol_fstype; + ondisk->vol_signature = HAMMER_FSBUF_VOLUME; + ondisk->vol_fsid = hmp->fsid; + ondisk->vol_rootvol = hmp->rootvol->vol_no; + ondisk->vol_no = vol_no; + ondisk->vol_count = vol_count; + ondisk->vol_version = hmp->version; + + /* + * Reserve space for (future) header junk, setup our poor-man's + * bigblock allocator. + */ + int64_t vol_alloc = HAMMER_BUFSIZE * 16; + + ondisk->vol_bot_beg = vol_alloc; + vol_alloc += boot_area_size; + ondisk->vol_mem_beg = vol_alloc; + vol_alloc += mem_area_size; + + /* + * The remaining area is the zone 2 buffer allocation area. These + * buffers + */ + ondisk->vol_buf_beg = vol_alloc; + ondisk->vol_buf_end = vol_size & ~(int64_t)HAMMER_BUFMASK; + + if (ondisk->vol_buf_end < ondisk->vol_buf_beg) { + kprintf("volume %d %s is too small to hold the volume header", + ondisk->vol_no, ondisk->vol_name); + error = EFTYPE; + goto late_failure; + } + + ondisk->vol_nblocks = (ondisk->vol_buf_end - ondisk->vol_buf_beg) / + HAMMER_BUFSIZE; + ondisk->vol_blocksize = HAMMER_BUFSIZE; + + /* + * Write volume header to disk + */ + error = bwrite(bp); + bp = NULL; + +late_failure: + if (bp) + brelse(bp); + VOP_CLOSE(devvp, FREAD|FWRITE); + if (devvp) + vrele(devvp); + return (error); +} diff --git a/sys/vfs/hammer/hammer_ioctl.c b/sys/vfs/hammer/hammer_ioctl.c index 91ef54701f..db8c060508 100644 --- a/sys/vfs/hammer/hammer_ioctl.c +++ b/sys/vfs/hammer/hammer_ioctl.c @@ -149,6 +149,13 @@ hammer_ioctl(hammer_inode_t ip, u_long com, caddr_t data, int fflag, (struct hammer_ioc_version *)data); } break; + case HAMMERIOC_EXPAND: + if (error == 0) { + error = hammer_ioc_expand(&trans, ip, + (struct hammer_ioc_expand *)data); + } + break; + default: error = EOPNOTSUPP; break; diff --git a/sys/vfs/hammer/hammer_ioctl.h b/sys/vfs/hammer/hammer_ioctl.h index 1bb8fb3f2b..770e61e211 100644 --- a/sys/vfs/hammer/hammer_ioctl.h +++ b/sys/vfs/hammer/hammer_ioctl.h @@ -335,6 +335,14 @@ struct hammer_ioc_version { char description[64]; }; +struct hammer_ioc_expand { + struct hammer_ioc_head head; + char device_name[MAXPATHLEN]; + int64_t vol_size; + int64_t boot_area_size; + int64_t mem_area_size; +}; + union hammer_ioc_mrecord_any { struct hammer_ioc_mrecord_head head; struct hammer_ioc_mrecord_rec rec; @@ -400,6 +408,7 @@ typedef union hammer_ioc_mrecord_any *hammer_ioc_mrecord_any_t; #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_EXPAND _IOWR('h',17,struct hammer_ioc_expand) #endif