sbin/hammer: Add hammer strip command master
authorTomohiro Kusumi <kusumi.tomohiro@gmail.com>
Sun, 4 Dec 2016 09:57:15 +0000 (18:57 +0900)
committerTomohiro Kusumi <kusumi.tomohiro@gmail.com>
Mon, 5 Dec 2016 17:50:34 +0000 (02:50 +0900)
This command is inspired by hammer recover command, and does
opposite of what recover command does.

This command zero clears zone-8(B-Tree) big-blocks, zone-9(meta)
big-blocks, and then the whole volume header, except that volume
signature field is overwritten with "STRIPPED" instead of zeros.
After running, a filesystem is no longer mountable or recoverable
with hammer recover command. This command is also fast as it only
zero clears good enough ondisk data to make it unmountable and
unrecoverable.

Keep in mind that this command does _not_ zero clear user data.
Users would normally use a software designed to completely shred
a filesystem. This command is not designed to shred a filesystem.
The name "strip" gives better idea of what it really does than
using "shred"/etc.

-- example
 # newfs_hammer -L TEST /dev/da1 /dev/da2 /dev/da3 > /dev/null
 # mount_hammer /dev/da1:/dev/da2:/dev/da3 /HAMMER
 # cd /HAMMER
 # dd if=/dev/urandom of=./out bs=1M count=120000
 120000+0 records in
 120000+0 records out
 125829120000 bytes transferred in 1766.417077 secs (71234094 bytes/sec)
 # cd
 # umount /HAMMER
 # hammer -f /dev/da1:/dev/da2:/dev/da3 strip
 You have requested that HAMMER filesystem (TEST) be stripped
 Do you really want to do this? [y/n] y
 Stripping HAMMER filesystem (TEST) in 5 4 3 2 1.. starting destruction pass
 8000000021000000
 9000000021800000
 800000019c000000
 800000030c000000
 800000047e000000
 80000005f7000000
 8000000767000000
 80000008d8000000
 8000000a51800000
 8000000bc5000000
 8000000d37800000
 8000000ead000000
 800000101e800000
 8000001193000000
 8000001304000000
 8000001478800000
 80000015ee000000
 8000001760800000
 80000018d1800000
 8000001a47000000
 8000001bb6000000
 801000013c000000
 /dev/da1
 /dev/da2
 /dev/da3
 # mount_hammer /dev/da1:/dev/da2:/dev/da3 /HAMMER
 mount: Invalid argument
 mount_hammer: /dev/da1: Invalid volume signature 4445505049525453

sbin/hammer/Makefile
sbin/hammer/cmd_strip.c [new file with mode: 0644]
sbin/hammer/hammer.8
sbin/hammer/hammer.c
sbin/hammer/hammer.h
sys/vfs/hammer/hammer_ondisk.c

index 54361cb..ea119a2 100644 (file)
@@ -5,7 +5,8 @@ SRCS=   hammer.c ondisk.c blockmap.c cache.c misc.c cycle.c \
        cmd_synctid.c cmd_stats.c cmd_remote.c \
        cmd_pfs.c cmd_snapshot.c cmd_mirror.c \
        cmd_cleanup.c cmd_info.c cmd_version.c cmd_volume.c \
-       cmd_config.c cmd_recover.c cmd_dedup.c cmd_abort.c
+       cmd_config.c cmd_recover.c cmd_dedup.c cmd_abort.c \
+       cmd_strip.c
 MAN=   hammer.8
 
 CFLAGS+= -I${.CURDIR}/../../sys
diff --git a/sbin/hammer/cmd_strip.c b/sbin/hammer/cmd_strip.c
new file mode 100644 (file)
index 0000000..7512396
--- /dev/null
@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) 2007-2016 The DragonFly Project.  All rights reserved.
+ *
+ * This code is derived from software contributed to The DragonFly Project
+ * by Matthew Dillon <dillon@backplane.com>
+ *
+ * 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"
+
+static void hammer_strip_bigblock(int zone, hammer_off_t offset);
+static void hammer_ask_yn(void);
+
+void
+hammer_cmd_strip(void)
+{
+       struct volume_info *vol;
+       hammer_blockmap_t rootmap;
+       hammer_blockmap_layer1_t layer1;
+       hammer_blockmap_layer2_t layer2;
+       struct buffer_info *buffer1 = NULL;
+       struct buffer_info *buffer2 = NULL;
+       hammer_off_t layer1_offset;
+       hammer_off_t layer2_offset;
+       hammer_off_t phys_offset;
+       hammer_off_t block_offset;
+       hammer_off_t offset;
+       int i, zone = HAMMER_ZONE_FREEMAP_INDEX;
+
+       hammer_ask_yn();
+
+       vol = get_root_volume();
+       rootmap = &vol->ondisk->vol0_blockmap[zone];
+       assert(rootmap->phys_offset != 0);
+
+       for (phys_offset = HAMMER_ZONE_ENCODE(zone, 0);
+            phys_offset < HAMMER_ZONE_ENCODE(zone, HAMMER_OFF_LONG_MASK);
+            phys_offset += HAMMER_BLOCKMAP_LAYER2) {
+               /*
+                * Dive layer 1.
+                */
+               layer1_offset = rootmap->phys_offset +
+                               HAMMER_BLOCKMAP_LAYER1_OFFSET(phys_offset);
+               layer1 = get_buffer_data(layer1_offset, &buffer1, 0);
+
+               if (layer1->phys_offset == HAMMER_BLOCKMAP_UNAVAIL)
+                       continue;
+
+               for (block_offset = 0;
+                    block_offset < HAMMER_BLOCKMAP_LAYER2;
+                    block_offset += HAMMER_BIGBLOCK_SIZE) {
+                       offset = phys_offset + block_offset;
+                       /*
+                        * Dive layer 2, each entry represents a big-block.
+                        */
+                       layer2_offset = layer1->phys_offset +
+                                       HAMMER_BLOCKMAP_LAYER2_OFFSET(block_offset);
+                       layer2 = get_buffer_data(layer2_offset, &buffer2, 0);
+
+                       if (layer2->zone == HAMMER_ZONE_BTREE_INDEX ||
+                           layer2->zone == HAMMER_ZONE_META_INDEX) {
+                               hammer_strip_bigblock(layer2->zone, offset);
+                               layer2->zone = HAMMER_ZONE_UNAVAIL_INDEX;
+                               layer2->append_off = HAMMER_BIGBLOCK_SIZE;
+                               layer2->bytes_free = 0;
+                               hammer_crc_set_layer2(layer2);
+                               buffer2->cache.modified = 1;
+                       } else if (layer2->zone == HAMMER_ZONE_UNAVAIL_INDEX) {
+                               break;
+                       }
+               }
+       }
+       rel_buffer(buffer1);
+       rel_buffer(buffer2);
+
+       for (i = 0; i < HAMMER_MAX_VOLUMES; i++) {
+               vol = get_volume(i);
+               if (vol) {
+                       printf("%s\n", vol->name);
+                       bzero(vol->ondisk, sizeof(*vol->ondisk));
+                       memcpy(&vol->ondisk->vol_signature, "STRIPPED", 8);
+               }
+       }
+
+       flush_all_volumes();
+}
+
+static void
+hammer_strip_bigblock(int zone, hammer_off_t offset)
+{
+       struct buffer_info *buffer = NULL;
+       int i;
+
+       assert(hammer_is_zone2_mapped_index(zone));
+       assert((offset & HAMMER_BIGBLOCK_MASK64) == 0);
+       assert((offset & HAMMER_BUFMASK) == 0);
+       offset = hammer_xlate_to_zoneX(zone, offset);
+
+       /*
+        * This format is taken from hammer blockmap.
+        */
+       if (VerboseOpt) {
+               printf("%016jx zone=%-2d vol=%-3d L1#=%-6d L2#=%-6d L1=%-7lu L2=%-7lu\n",
+                       offset,
+                       zone,
+                       HAMMER_VOL_DECODE(offset),
+                       HAMMER_BLOCKMAP_LAYER1_INDEX(offset),
+                       HAMMER_BLOCKMAP_LAYER2_INDEX(offset),
+                       HAMMER_BLOCKMAP_LAYER1_OFFSET(offset),
+                       HAMMER_BLOCKMAP_LAYER2_OFFSET(offset));
+       } else {
+               printf("%016jx\n", offset);
+       }
+
+       for (i = 0; i < HAMMER_BIGBLOCK_SIZE; i += HAMMER_BUFSIZE) {
+               get_buffer_data(offset + i, &buffer, 1);
+               assert(buffer);
+       }
+}
+
+static void
+hammer_ask_yn(void)
+{
+       struct volume_info *vol;
+       int i;
+
+       vol = get_root_volume();
+
+       /*
+        * This format is taken from hammer pfs-destroy.
+        */
+       printf("You have requested that HAMMER filesystem (%s) be stripped\n",
+               vol->ondisk->vol_label);
+       printf("Do you really want to do this? [y/n] ");
+       fflush(stdout);
+
+       if (getyn() == 0) {
+               fprintf(stderr, "No action taken\n");
+               exit(1);
+       }
+
+       printf("Stripping HAMMER filesystem (%s)", vol->ondisk->vol_label);
+
+       if (DebugOpt) {
+               printf("\n");
+       } else {
+               printf(" in");
+               for (i = 5; i; --i) {
+                       printf(" %d", i);
+                       fflush(stdout);
+                       sleep(1);
+               }
+               printf(".. starting destruction pass\n");
+       }
+}
index 089dbb1..338cb61 100644 (file)
@@ -30,7 +30,7 @@
 .\" OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.Dd April 9, 2016
+.Dd December 4, 2016
 .Dt HAMMER 8
 .Os
 .Sh NAME
@@ -492,6 +492,31 @@ recovering data from a dead filesystem.
 This command needs the
 .Fl f Ar blkdevs
 option.
+.\" ==== strip ====
+.It Cm strip
+Strip
+.Nm HAMMER
+filesystem volume header and other meta-data by overwriting them with irrelevant data.
+.Nm HAMMER
+volumes need to be unmounted.
+.Pp
+This is a fast way to make
+.Nm HAMMER
+filesystem unmountable and unrecoverable.
+After running this command,
+.Nm HAMMER
+filesystem data is no longer recoverable using
+.Cm recover
+command, although the data still exists within the
+.Nm HAMMER
+volumes.
+As safety measure the
+.Fl y
+flag have no effect on this directive.
+.Pp
+This command needs the
+.Fl f Ar blkdevs
+option.
 .\" ==== namekey1 ====
 .It Cm namekey1 Ar filename
 Generate a
index be8f9a1..b30683d 100644 (file)
@@ -552,6 +552,12 @@ main(int ac, char **av)
                hammer_cmd_checkmap();
                exit(0);
        }
+       if (strcmp(av[0], "strip") == 0) {
+               hammer_parsedevs(blkdevs, O_RDWR);
+               hammer_cmd_strip();
+               exit(0);
+       }
+
        usage(1);
        /* not reached */
        return(0);
@@ -712,6 +718,7 @@ usage(int exit_code)
                "hammer -f blkdevs [-qqq] show [lo:objid]\n"
                "hammer -f blkdevs show-undo\n"
                "hammer -f blkdevs recover <target_dir>\n"
+               "hammer -f blkdevs strip\n"
        );
 
        fprintf(stderr, "\nHAMMER utility version 5+ commands:\n");
index a9ad333..a16cc2e 100644 (file)
@@ -137,6 +137,7 @@ void hammer_cmd_volume_blkdevs(char **av, int ac);
 void hammer_cmd_dedup_simulate(char **av, int ac);
 void hammer_cmd_dedup(char **av, int ac);
 void hammer_cmd_abort_cleanup(char **av, int ac);
+void hammer_cmd_strip(void);
 
 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 83db7bc..a0193f5 100644 (file)
@@ -188,8 +188,8 @@ hammer_install_volume(hammer_mount_t hmp, const char *volname,
        if (ronly == 0 && data) {
                img = (hammer_volume_ondisk_t)data;
                if (ondisk->vol_signature == HAMMER_FSBUF_VOLUME) {
-                       hkprintf("Formatting of valid HAMMER volume "
-                               "%s denied. Erase with dd!\n", volname);
+                       hkprintf("Formatting of valid HAMMER volume %s denied. "
+                               "Erase with hammer strip or dd!\n", volname);
                        error = EFTYPE;
                        goto late_failure;
                }