Merge branch 'master' of ssh://crater.dragonflybsd.org/repository/git/dragonfly
authorMichael Neumann <mneumann@ntecs.de>
Tue, 14 Jul 2009 14:01:40 +0000 (16:01 +0200)
committerMichael Neumann <mneumann@ntecs.de>
Tue, 14 Jul 2009 14:01:40 +0000 (16:01 +0200)
sbin/hammer/Makefile
sbin/hammer/cmd_expand.c [new file with mode: 0644]
sbin/hammer/hammer.c
sbin/hammer/hammer.h
sys/conf/files
sys/vfs/hammer/Makefile
sys/vfs/hammer/hammer.h
sys/vfs/hammer/hammer_expand.c [new file with mode: 0644]
sys/vfs/hammer/hammer_ioctl.c
sys/vfs/hammer/hammer_ioctl.h

index 9900c41..32ae468 100644 (file)
@@ -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 (file)
index 0000000..4da637e
--- /dev/null
@@ -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 <dillon@backplane.com> and
+ * Michael Neumann <mneumann@ntecs.de>
+ *
+ * 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 <string.h>
+
+static uint64_t check_volume(const char *vol_name);
+static void expand_usage(int exit_code);
+
+/*
+ * expand <filesystem> <device>
+ */
+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 <filesystem> <device>\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;
+}
index 18e3333..17eb81a 100644 (file)
@@ -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:]<filesystem>\n"
                "hammer version <filesystem>\n"
                "hammer version-upgrade <filesystem> version# [force]\n"
+               "hammer expand <filesystem> <device>\n"
        );
        exit(exit_code);
 }
index 4d05a1c..d055888 100644 (file)
@@ -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);
index 4e431a2..459cd51 100644 (file)
@@ -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
index b687619..f40e0dc 100644 (file)
@@ -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 <bsd.kmod.mk>
index 2696acc..d0c7952 100644 (file)
@@ -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 (file)
index 0000000..0d21f85
--- /dev/null
@@ -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 <dillon@backplane.com> and
+ * Michael Neumann <mneumann@ntecs.de>
+ *
+ * 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 <sys/fcntl.h>
+#include <sys/nlookup.h>
+#include <sys/buf.h>
+
+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);
+}
index 91ef547..db8c060 100644 (file)
@@ -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;
index 1bb8fb3..770e61e 100644 (file)
@@ -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