12d60b848STomohiro Kusumi /* 22d60b848STomohiro Kusumi * SPDX-License-Identifier: BSD-3-Clause 32d60b848STomohiro Kusumi * 42d60b848STomohiro Kusumi * Copyright (c) 2022 Tomohiro Kusumi <tkusumi@netbsd.org> 52d60b848STomohiro Kusumi * Copyright (c) 2011-2022 The DragonFly Project. All rights reserved. 62d60b848STomohiro Kusumi * 72d60b848STomohiro Kusumi * Redistribution and use in source and binary forms, with or without 82d60b848STomohiro Kusumi * modification, are permitted provided that the following conditions 92d60b848STomohiro Kusumi * are met: 102d60b848STomohiro Kusumi * 112d60b848STomohiro Kusumi * 1. Redistributions of source code must retain the above copyright 122d60b848STomohiro Kusumi * notice, this list of conditions and the following disclaimer. 132d60b848STomohiro Kusumi * 2. Redistributions in binary form must reproduce the above copyright 142d60b848STomohiro Kusumi * notice, this list of conditions and the following disclaimer in 152d60b848STomohiro Kusumi * the documentation and/or other materials provided with the 162d60b848STomohiro Kusumi * distribution. 172d60b848STomohiro Kusumi * 3. Neither the name of The DragonFly Project nor the names of its 182d60b848STomohiro Kusumi * contributors may be used to endorse or promote products derived 192d60b848STomohiro Kusumi * from this software without specific, prior written permission. 202d60b848STomohiro Kusumi * 212d60b848STomohiro Kusumi * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 222d60b848STomohiro Kusumi * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 232d60b848STomohiro Kusumi * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 242d60b848STomohiro Kusumi * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 252d60b848STomohiro Kusumi * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 262d60b848STomohiro Kusumi * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 272d60b848STomohiro Kusumi * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 282d60b848STomohiro Kusumi * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 292d60b848STomohiro Kusumi * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 302d60b848STomohiro Kusumi * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 312d60b848STomohiro Kusumi * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 322d60b848STomohiro Kusumi * SUCH DAMAGE. 332d60b848STomohiro Kusumi */ 342d60b848STomohiro Kusumi 352d60b848STomohiro Kusumi #if HAVE_NBTOOL_CONFIG_H 362d60b848STomohiro Kusumi #include "nbtool_config.h" 372d60b848STomohiro Kusumi #endif 382d60b848STomohiro Kusumi 392d60b848STomohiro Kusumi #include <sys/param.h> 402d60b848STomohiro Kusumi #include <sys/stat.h> 412d60b848STomohiro Kusumi #include <sys/sysctl.h> 422d60b848STomohiro Kusumi #include <sys/mman.h> 432d60b848STomohiro Kusumi 442d60b848STomohiro Kusumi #include <stdio.h> 452d60b848STomohiro Kusumi #include <stdlib.h> 462d60b848STomohiro Kusumi #include <stdbool.h> 472d60b848STomohiro Kusumi #include <string.h> 48465e1141STomohiro Kusumi #include <ctype.h> 492d60b848STomohiro Kusumi #include <unistd.h> 502d60b848STomohiro Kusumi #include <fcntl.h> 512d60b848STomohiro Kusumi #include <time.h> 522d60b848STomohiro Kusumi #include <err.h> 532d60b848STomohiro Kusumi #include <assert.h> 542d60b848STomohiro Kusumi #include <util.h> 552d60b848STomohiro Kusumi 562d60b848STomohiro Kusumi #include "makefs.h" 572d60b848STomohiro Kusumi #include "hammer2.h" 582d60b848STomohiro Kusumi 592d60b848STomohiro Kusumi #define APRINTF(X, ...) \ 602d60b848STomohiro Kusumi printf("%s: " X, __func__, ## __VA_ARGS__) 612d60b848STomohiro Kusumi 623999233bSTomohiro Kusumi static void hammer2_parse_pfs_opts(const char *, fsinfo_t *); 63f804c425STomohiro Kusumi static void hammer2_parse_inode_opts(const char *, fsinfo_t *); 642d60b848STomohiro Kusumi static void hammer2_dump_fsinfo(fsinfo_t *); 652d60b848STomohiro Kusumi static int hammer2_create_image(const char *, fsinfo_t *); 666bcbb706STomohiro Kusumi static int hammer2_populate_dir(struct m_vnode *, const char *, fsnode *, 672d60b848STomohiro Kusumi fsnode *, fsinfo_t *, int); 682d60b848STomohiro Kusumi static void hammer2_validate(const char *, fsnode *, fsinfo_t *); 692d60b848STomohiro Kusumi static void hammer2_size_dir(fsnode *, fsinfo_t *); 706bcbb706STomohiro Kusumi static int hammer2_write_file(struct m_vnode *, const char *, fsnode *); 71f72350acSTomohiro Kusumi static int hammer2_version_get(struct m_vnode *); 729a149651STomohiro Kusumi static int hammer2_pfs_get(struct m_vnode *); 739a149651STomohiro Kusumi static int hammer2_pfs_lookup(struct m_vnode *, const char *); 749a149651STomohiro Kusumi static int hammer2_pfs_create(struct m_vnode *, const char *); 759a149651STomohiro Kusumi static int hammer2_pfs_delete(struct m_vnode *, const char *); 769a149651STomohiro Kusumi static int hammer2_pfs_snapshot(struct m_vnode *, const char *, const char *); 77465e1141STomohiro Kusumi static int hammer2_inode_getx(struct m_vnode *, const char *); 78465e1141STomohiro Kusumi static int hammer2_inode_setcheck(struct m_vnode *, const char *); 79465e1141STomohiro Kusumi static int hammer2_inode_setcomp(struct m_vnode *, const char *); 803999233bSTomohiro Kusumi static int hammer2_bulkfree(struct m_vnode *); 813999233bSTomohiro Kusumi static int hammer2_destroy_path(struct m_vnode *, const char *); 823999233bSTomohiro Kusumi static int hammer2_destroy_inum(struct m_vnode *, hammer2_tid_t); 833999233bSTomohiro Kusumi static int hammer2_growfs(struct m_vnode *, hammer2_off_t); 846857f034STomohiro Kusumi static void unittest_trim_slash(void); 852d60b848STomohiro Kusumi 86ddd1d3d1STomohiro Kusumi fsnode *hammer2_curnode; 87ddd1d3d1STomohiro Kusumi 882d60b848STomohiro Kusumi void 892d60b848STomohiro Kusumi hammer2_prep_opts(fsinfo_t *fsopts) 902d60b848STomohiro Kusumi { 912d60b848STomohiro Kusumi hammer2_makefs_options_t *h2_opt = ecalloc(1, sizeof(*h2_opt)); 922d60b848STomohiro Kusumi hammer2_mkfs_options_t *opt = &h2_opt->mkfs_options; 932d60b848STomohiro Kusumi 942d60b848STomohiro Kusumi const option_t hammer2_options[] = { 952d60b848STomohiro Kusumi /* newfs_hammer2(8) compatible options */ 962d60b848STomohiro Kusumi { 'b', "BootAreaSize", NULL, OPT_STRBUF, 0, 0, "boot area size" }, 972d60b848STomohiro Kusumi { 'r', "AuxAreaSize", NULL, OPT_STRBUF, 0, 0, "aux area size" }, 982d60b848STomohiro Kusumi { 'V', "Hammer2Version", NULL, OPT_STRBUF, 0, 0, "file system version" }, 992d60b848STomohiro Kusumi { 'L', "Label", NULL, OPT_STRBUF, 0, 0, "PFS label" }, 1002d60b848STomohiro Kusumi /* makefs(8) specific options */ 1012d60b848STomohiro Kusumi { 'm', "MountLabel", NULL, OPT_STRBUF, 0, 0, "destination PFS label" }, 1022d60b848STomohiro Kusumi { 'v', "NumVolhdr", &h2_opt->num_volhdr, OPT_INT32, 1032d60b848STomohiro Kusumi 1, HAMMER2_NUM_VOLHDRS, "number of volume headers" }, 1042d60b848STomohiro Kusumi { 'd', "Hammer2Debug", NULL, OPT_STRBUF, 0, 0, "debug tunable" }, 10548ed4577STomohiro Kusumi { 'E', "EmergencyMode", &h2_opt->emergency_mode, OPT_BOOL, 0, 0, 10648ed4577STomohiro Kusumi "emergency mode" }, 1073999233bSTomohiro Kusumi { 'P', "PFS", NULL, OPT_STRBUF, 0, 0, "offline PFS" }, 108f804c425STomohiro Kusumi { 'I', "Inode", NULL, OPT_STRBUF, 0, 0, "offline inode" }, 1099a149651STomohiro Kusumi { 'B', "Bulkfree", NULL, OPT_STRBUF, 0, 0, "offline bulkfree" }, 110917508cdSTomohiro Kusumi { 'D', "Destroy", NULL, OPT_STRBUF, 0, 0, "offline destroy" }, 1119a149651STomohiro Kusumi { 'G', "Growfs", NULL, OPT_STRBUF, 0, 0, "offline growfs" }, 1122d60b848STomohiro Kusumi { .name = NULL }, 1132d60b848STomohiro Kusumi }; 1142d60b848STomohiro Kusumi 1152d60b848STomohiro Kusumi hammer2_mkfs_init(opt); 1162d60b848STomohiro Kusumi 1172d60b848STomohiro Kusumi /* make this tunable ? */ 1182d60b848STomohiro Kusumi assert(opt->CompType == HAMMER2_COMP_NEWFS_DEFAULT); 1192d60b848STomohiro Kusumi assert(opt->CheckType == HAMMER2_CHECK_XXHASH64); 1202d60b848STomohiro Kusumi 1212d60b848STomohiro Kusumi /* force debug mode for mkfs */ 1222d60b848STomohiro Kusumi opt->DebugOpt = 1; 1232d60b848STomohiro Kusumi 1242d60b848STomohiro Kusumi fsopts->fs_specific = h2_opt; 1252d60b848STomohiro Kusumi fsopts->fs_options = copy_opts(hammer2_options); 1262d60b848STomohiro Kusumi fsopts->sectorsize = DEV_BSIZE; 1272d60b848STomohiro Kusumi } 1282d60b848STomohiro Kusumi 1292d60b848STomohiro Kusumi void 1302d60b848STomohiro Kusumi hammer2_cleanup_opts(fsinfo_t *fsopts) 1312d60b848STomohiro Kusumi { 1322d60b848STomohiro Kusumi hammer2_makefs_options_t *h2_opt = fsopts->fs_specific; 1332d60b848STomohiro Kusumi hammer2_mkfs_options_t *opt = &h2_opt->mkfs_options; 1342d60b848STomohiro Kusumi 1352d60b848STomohiro Kusumi hammer2_mkfs_cleanup(opt); 1362d60b848STomohiro Kusumi 1372d60b848STomohiro Kusumi free(h2_opt); 1382d60b848STomohiro Kusumi free(fsopts->fs_options); 1392d60b848STomohiro Kusumi } 1402d60b848STomohiro Kusumi 1412d60b848STomohiro Kusumi int 1422d60b848STomohiro Kusumi hammer2_parse_opts(const char *option, fsinfo_t *fsopts) 1432d60b848STomohiro Kusumi { 1442d60b848STomohiro Kusumi hammer2_makefs_options_t *h2_opt = fsopts->fs_specific; 1452d60b848STomohiro Kusumi hammer2_mkfs_options_t *opt = &h2_opt->mkfs_options; 1462d60b848STomohiro Kusumi 1472d60b848STomohiro Kusumi option_t *hammer2_options = fsopts->fs_options; 1482d60b848STomohiro Kusumi char buf[1024]; /* > HAMMER2_INODE_MAXNAME */ 1492d60b848STomohiro Kusumi int i; 1502d60b848STomohiro Kusumi 1512d60b848STomohiro Kusumi assert(option != NULL); 1522d60b848STomohiro Kusumi assert(fsopts != NULL); 1532d60b848STomohiro Kusumi 1542d60b848STomohiro Kusumi if (debug & DEBUG_FS_PARSE_OPTS) 1552d60b848STomohiro Kusumi APRINTF("got `%s'\n", option); 1562d60b848STomohiro Kusumi 1572d60b848STomohiro Kusumi i = set_option(hammer2_options, option, buf, sizeof(buf)); 1582d60b848STomohiro Kusumi if (i == -1) 1592d60b848STomohiro Kusumi return 0; 1602d60b848STomohiro Kusumi 1612d60b848STomohiro Kusumi if (hammer2_options[i].name == NULL) 1622d60b848STomohiro Kusumi abort(); 1632d60b848STomohiro Kusumi 1642d60b848STomohiro Kusumi switch (hammer2_options[i].letter) { 1652d60b848STomohiro Kusumi case 'b': 1662d60b848STomohiro Kusumi opt->BootAreaSize = getsize(buf, HAMMER2_NEWFS_ALIGN, 1672d60b848STomohiro Kusumi HAMMER2_BOOT_MAX_BYTES, 2); 1682d60b848STomohiro Kusumi break; 1692d60b848STomohiro Kusumi case 'r': 1702d60b848STomohiro Kusumi opt->AuxAreaSize = getsize(buf, HAMMER2_NEWFS_ALIGN, 1712d60b848STomohiro Kusumi HAMMER2_AUX_MAX_BYTES, 2); 1722d60b848STomohiro Kusumi break; 1732d60b848STomohiro Kusumi case 'V': 174f72350acSTomohiro Kusumi if (strlen(buf) == 0) { 175f72350acSTomohiro Kusumi h2_opt->ioctl_cmd = HAMMER2IOC_VERSION_GET; 176f72350acSTomohiro Kusumi } else { 1772d60b848STomohiro Kusumi opt->Hammer2Version = strtol(buf, NULL, 0); 1782d60b848STomohiro Kusumi if (opt->Hammer2Version < HAMMER2_VOL_VERSION_MIN || 1792d60b848STomohiro Kusumi opt->Hammer2Version >= HAMMER2_VOL_VERSION_WIP) 1802d60b848STomohiro Kusumi errx(1, "I don't understand how to format " 1812d60b848STomohiro Kusumi "HAMMER2 version %d", 1822d60b848STomohiro Kusumi opt->Hammer2Version); 183f72350acSTomohiro Kusumi } 1842d60b848STomohiro Kusumi break; 1852d60b848STomohiro Kusumi case 'L': 1862d60b848STomohiro Kusumi h2_opt->label_specified = 1; 1872d60b848STomohiro Kusumi if (strcasecmp(buf, "none") == 0) 1882d60b848STomohiro Kusumi break; 1892d60b848STomohiro Kusumi if (opt->NLabels >= MAXLABELS) 1902d60b848STomohiro Kusumi errx(1, "Limit of %d local labels", MAXLABELS - 1); 1912d60b848STomohiro Kusumi if (strlen(buf) == 0) 1922d60b848STomohiro Kusumi errx(1, "Volume label '%s' cannot be 0-length", buf); 1932d60b848STomohiro Kusumi if (strlen(buf) >= HAMMER2_INODE_MAXNAME) 1942d60b848STomohiro Kusumi errx(1, "Volume label '%s' is too long (%d chars max)", 1952d60b848STomohiro Kusumi buf, HAMMER2_INODE_MAXNAME - 1); 1962d60b848STomohiro Kusumi opt->Label[opt->NLabels++] = strdup(buf); 1972d60b848STomohiro Kusumi break; 1982d60b848STomohiro Kusumi case 'm': 1992d60b848STomohiro Kusumi if (strlen(buf) == 0) 2002d60b848STomohiro Kusumi errx(1, "Volume label '%s' cannot be 0-length", buf); 2012d60b848STomohiro Kusumi if (strlen(buf) >= HAMMER2_INODE_MAXNAME) 2022d60b848STomohiro Kusumi errx(1, "Volume label '%s' is too long (%d chars max)", 2032d60b848STomohiro Kusumi buf, HAMMER2_INODE_MAXNAME - 1); 2042d60b848STomohiro Kusumi strlcpy(h2_opt->mount_label, buf, sizeof(h2_opt->mount_label)); 2052d60b848STomohiro Kusumi break; 2062d60b848STomohiro Kusumi case 'd': 2072d60b848STomohiro Kusumi hammer2_debug = strtoll(buf, NULL, 0); 2082d60b848STomohiro Kusumi break; 2093999233bSTomohiro Kusumi case 'P': 2103999233bSTomohiro Kusumi if (strlen(buf) == 0) 2113999233bSTomohiro Kusumi errx(1, "PFS argument '%s' cannot be 0-length", buf); 2123999233bSTomohiro Kusumi hammer2_parse_pfs_opts(buf, fsopts); 2133999233bSTomohiro Kusumi break; 214f804c425STomohiro Kusumi case 'I': 215f804c425STomohiro Kusumi if (strlen(buf) == 0) 216f804c425STomohiro Kusumi errx(1, "Inode argument '%s' cannot be 0-length", buf); 217f804c425STomohiro Kusumi hammer2_parse_inode_opts(buf, fsopts); 218f804c425STomohiro Kusumi break; 2199a149651STomohiro Kusumi case 'B': 2209a149651STomohiro Kusumi h2_opt->ioctl_cmd = HAMMER2IOC_BULKFREE_SCAN; 2219a149651STomohiro Kusumi break; 222917508cdSTomohiro Kusumi case 'D': 2239a149651STomohiro Kusumi h2_opt->ioctl_cmd = HAMMER2IOC_DESTROY; 224b4807901STomohiro Kusumi if (strlen(buf) == 0) 225b4807901STomohiro Kusumi errx(1, "Destroy argument '%s' cannot be 0-length", buf); 226917508cdSTomohiro Kusumi if (buf[0] == '/') { 2276857f034STomohiro Kusumi strlcpy(h2_opt->destroy_path, buf, 228917508cdSTomohiro Kusumi sizeof(h2_opt->destroy_path)); 229b4807901STomohiro Kusumi } else if (strncmp(buf, "0x", 2) == 0 || 230917508cdSTomohiro Kusumi (buf[0] >= '0' && buf[0] <= '9')) { 231917508cdSTomohiro Kusumi h2_opt->destroy_inum = strtoull(buf, NULL, 0); 232917508cdSTomohiro Kusumi if (errno) 233917508cdSTomohiro Kusumi err(1, "strtoull"); 234917508cdSTomohiro Kusumi } else { 235917508cdSTomohiro Kusumi errx(1, "Invalid destroy argument %s", buf); 236917508cdSTomohiro Kusumi } 237917508cdSTomohiro Kusumi break; 2389a149651STomohiro Kusumi case 'G': 2399a149651STomohiro Kusumi h2_opt->ioctl_cmd = HAMMER2IOC_GROWFS; 2409a149651STomohiro Kusumi break; 2412d60b848STomohiro Kusumi default: 2422d60b848STomohiro Kusumi break; 2432d60b848STomohiro Kusumi } 2442d60b848STomohiro Kusumi 2456857f034STomohiro Kusumi if (hammer2_debug && h2_opt->ioctl_cmd) 2466857f034STomohiro Kusumi unittest_trim_slash(); 2476857f034STomohiro Kusumi 2482d60b848STomohiro Kusumi return 1; 2492d60b848STomohiro Kusumi } 2502d60b848STomohiro Kusumi 2512d60b848STomohiro Kusumi void 2522d60b848STomohiro Kusumi hammer2_makefs(const char *image, const char *dir, fsnode *root, 2532d60b848STomohiro Kusumi fsinfo_t *fsopts) 2542d60b848STomohiro Kusumi { 2552d60b848STomohiro Kusumi hammer2_makefs_options_t *h2_opt = fsopts->fs_specific; 2562d60b848STomohiro Kusumi struct mount mp; 2572d60b848STomohiro Kusumi struct hammer2_mount_info info; 2586bcbb706STomohiro Kusumi struct m_vnode devvp, *vroot; 2592d60b848STomohiro Kusumi hammer2_inode_t *iroot; 2602d60b848STomohiro Kusumi struct timeval start; 2612d60b848STomohiro Kusumi int error; 2622d60b848STomohiro Kusumi 26370e962f7STomohiro Kusumi /* ioctl commands could have NULL dir / root */ 2642d60b848STomohiro Kusumi assert(image != NULL); 2652d60b848STomohiro Kusumi assert(fsopts != NULL); 2662d60b848STomohiro Kusumi 2672d60b848STomohiro Kusumi if (debug & DEBUG_FS_MAKEFS) 2682d60b848STomohiro Kusumi APRINTF("image \"%s\" directory \"%s\" root %p\n", 2692d60b848STomohiro Kusumi image, dir, root); 2702d60b848STomohiro Kusumi 2712d60b848STomohiro Kusumi /* validate tree and options */ 2722d60b848STomohiro Kusumi TIMER_START(start); 2732d60b848STomohiro Kusumi hammer2_validate(dir, root, fsopts); 2742d60b848STomohiro Kusumi TIMER_RESULTS(start, "hammer2_validate"); 2752d60b848STomohiro Kusumi 2769a149651STomohiro Kusumi if (h2_opt->ioctl_cmd) { 277b4807901STomohiro Kusumi /* open existing image */ 278b4807901STomohiro Kusumi fsopts->fd = open(image, O_RDWR); 279b4807901STomohiro Kusumi if (fsopts->fd < 0) 280b4807901STomohiro Kusumi err(1, "failed to open `%s'", image); 281b4807901STomohiro Kusumi } else { 2822d60b848STomohiro Kusumi /* create image */ 2832d60b848STomohiro Kusumi TIMER_START(start); 2842d60b848STomohiro Kusumi if (hammer2_create_image(image, fsopts) == -1) 2852d60b848STomohiro Kusumi errx(1, "image file `%s' not created", image); 2862d60b848STomohiro Kusumi TIMER_RESULTS(start, "hammer2_create_image"); 287a63188c8STomohiro Kusumi } 288a63188c8STomohiro Kusumi assert(fsopts->fd > 0); 2892d60b848STomohiro Kusumi 2902d60b848STomohiro Kusumi if (debug & DEBUG_FS_MAKEFS) 2912d60b848STomohiro Kusumi putchar('\n'); 2922d60b848STomohiro Kusumi 2932d60b848STomohiro Kusumi /* vfs init */ 2942d60b848STomohiro Kusumi error = hammer2_vfs_init(); 2952d60b848STomohiro Kusumi if (error) 2962d60b848STomohiro Kusumi errx(1, "failed to vfs init, error %d", error); 2972d60b848STomohiro Kusumi 2982d60b848STomohiro Kusumi /* mount image */ 2992d60b848STomohiro Kusumi memset(&devvp, 0, sizeof(devvp)); 3002d60b848STomohiro Kusumi devvp.fs = fsopts; 3012d60b848STomohiro Kusumi memset(&mp, 0, sizeof(mp)); 3022d60b848STomohiro Kusumi memset(&info, 0, sizeof(info)); 3032d60b848STomohiro Kusumi error = hammer2_vfs_mount(&devvp, &mp, h2_opt->mount_label, &info); 3042d60b848STomohiro Kusumi if (error) 3052d60b848STomohiro Kusumi errx(1, "failed to mount, error %d", error); 3062d60b848STomohiro Kusumi assert(mp.mnt_data); 3072d60b848STomohiro Kusumi 3082d60b848STomohiro Kusumi /* get root vnode */ 3092d60b848STomohiro Kusumi vroot = NULL; 3102d60b848STomohiro Kusumi error = hammer2_vfs_root(&mp, &vroot); 3112d60b848STomohiro Kusumi if (error) 3122d60b848STomohiro Kusumi errx(1, "failed to get root vnode, error %d", error); 3132d60b848STomohiro Kusumi assert(vroot); 3142d60b848STomohiro Kusumi 3152d60b848STomohiro Kusumi iroot = VTOI(vroot); 3162d60b848STomohiro Kusumi assert(iroot); 317f8a1147cSTomohiro Kusumi printf("root inode inum %lld, mode 0%o, refs %d\n", 318f8a1147cSTomohiro Kusumi (long long)iroot->meta.inum, iroot->meta.mode, iroot->refs); 3192d60b848STomohiro Kusumi 32048ed4577STomohiro Kusumi if (h2_opt->emergency_mode) 32148ed4577STomohiro Kusumi hammer2_ioctl_emerg_mode(iroot, 1); 32248ed4577STomohiro Kusumi 3239a149651STomohiro Kusumi switch (h2_opt->ioctl_cmd) { 324f72350acSTomohiro Kusumi case HAMMER2IOC_VERSION_GET: 325f72350acSTomohiro Kusumi printf("version get `%s'\n", image); 326f72350acSTomohiro Kusumi TIMER_START(start); 327f72350acSTomohiro Kusumi error = hammer2_version_get(vroot); 328f72350acSTomohiro Kusumi if (error) 329f72350acSTomohiro Kusumi errx(1, "version get `%s' failed '%s'", image, 330f72350acSTomohiro Kusumi strerror(error)); 331f72350acSTomohiro Kusumi TIMER_RESULTS(start, "hammer2_version_get"); 332f72350acSTomohiro Kusumi break; 3339a149651STomohiro Kusumi case HAMMER2IOC_PFS_GET: 3343999233bSTomohiro Kusumi printf("PFS %s `%s'\n", h2_opt->pfs_cmd_name, image); 3353999233bSTomohiro Kusumi TIMER_START(start); 3369a149651STomohiro Kusumi error = hammer2_pfs_get(vroot); 3379a149651STomohiro Kusumi if (error) 3389a149651STomohiro Kusumi errx(1, "PFS %s`%s' failed '%s'", h2_opt->pfs_cmd_name, 3399a149651STomohiro Kusumi image, strerror(error)); 3409a149651STomohiro Kusumi TIMER_RESULTS(start, "hammer2_pfs_get"); 3419a149651STomohiro Kusumi break; 3429a149651STomohiro Kusumi case HAMMER2IOC_PFS_LOOKUP: 3439a149651STomohiro Kusumi printf("PFS %s `%s'\n", h2_opt->pfs_cmd_name, image); 3449a149651STomohiro Kusumi TIMER_START(start); 3459a149651STomohiro Kusumi error = hammer2_pfs_lookup(vroot, h2_opt->pfs_name); 3469a149651STomohiro Kusumi if (error) 3479a149651STomohiro Kusumi errx(1, "PFS %s`%s' failed '%s'", h2_opt->pfs_cmd_name, 3489a149651STomohiro Kusumi image, strerror(error)); 3499a149651STomohiro Kusumi TIMER_RESULTS(start, "hammer2_pfs_lookup"); 3509a149651STomohiro Kusumi break; 3519a149651STomohiro Kusumi case HAMMER2IOC_PFS_CREATE: 3529a149651STomohiro Kusumi printf("PFS %s `%s'\n", h2_opt->pfs_cmd_name, image); 3539a149651STomohiro Kusumi TIMER_START(start); 3549a149651STomohiro Kusumi error = hammer2_pfs_create(vroot, h2_opt->pfs_name); 3559a149651STomohiro Kusumi if (error) 3569a149651STomohiro Kusumi errx(1, "PFS %s`%s' failed '%s'", h2_opt->pfs_cmd_name, 3579a149651STomohiro Kusumi image, strerror(error)); 3589a149651STomohiro Kusumi TIMER_RESULTS(start, "hammer2_pfs_create"); 3599a149651STomohiro Kusumi break; 3609a149651STomohiro Kusumi case HAMMER2IOC_PFS_DELETE: 3619a149651STomohiro Kusumi printf("PFS %s `%s'\n", h2_opt->pfs_cmd_name, image); 3629a149651STomohiro Kusumi TIMER_START(start); 3639a149651STomohiro Kusumi error = hammer2_pfs_delete(vroot, h2_opt->pfs_name); 3649a149651STomohiro Kusumi if (error) 3659a149651STomohiro Kusumi errx(1, "PFS %s`%s' failed '%s'", h2_opt->pfs_cmd_name, 3669a149651STomohiro Kusumi image, strerror(error)); 3679a149651STomohiro Kusumi TIMER_RESULTS(start, "hammer2_pfs_delete"); 3689a149651STomohiro Kusumi break; 3699a149651STomohiro Kusumi case HAMMER2IOC_PFS_SNAPSHOT: 3709a149651STomohiro Kusumi printf("PFS %s `%s'\n", h2_opt->pfs_cmd_name, image); 3719a149651STomohiro Kusumi TIMER_START(start); 3729a149651STomohiro Kusumi error = hammer2_pfs_snapshot(vroot, h2_opt->pfs_name, 37306d1ac82STomohiro Kusumi h2_opt->mount_label); 37406d1ac82STomohiro Kusumi if (error) 37506d1ac82STomohiro Kusumi errx(1, "PFS %s`%s' failed '%s'", h2_opt->pfs_cmd_name, 37606d1ac82STomohiro Kusumi image, strerror(error)); 3779a149651STomohiro Kusumi TIMER_RESULTS(start, "hammer2_pfs_snapshot"); 3789a149651STomohiro Kusumi break; 379f804c425STomohiro Kusumi case HAMMER2IOC_INODE_GET: 380465e1141STomohiro Kusumi printf("inode %s `%s'\n", h2_opt->inode_cmd_name, image); 381f804c425STomohiro Kusumi TIMER_START(start); 382f804c425STomohiro Kusumi error = hammer2_inode_getx(vroot, h2_opt->inode_path); 383f804c425STomohiro Kusumi if (error) 384465e1141STomohiro Kusumi errx(1, "inode %s `%s' failed '%s'", 385465e1141STomohiro Kusumi h2_opt->inode_cmd_name, image, strerror(error)); 386f804c425STomohiro Kusumi TIMER_RESULTS(start, "hammer2_inode_getx"); 387f804c425STomohiro Kusumi break; 388465e1141STomohiro Kusumi case HAMMER2IOC_INODE_SET: 389465e1141STomohiro Kusumi printf("inode %s `%s'\n", h2_opt->inode_cmd_name, image); 390465e1141STomohiro Kusumi TIMER_START(start); 391465e1141STomohiro Kusumi if (!strcmp(h2_opt->inode_cmd_name, "setcheck")) { 392465e1141STomohiro Kusumi error = hammer2_inode_setcheck(vroot, 393465e1141STomohiro Kusumi h2_opt->inode_path); 394465e1141STomohiro Kusumi if (error) 395465e1141STomohiro Kusumi errx(1, "inode %s `%s' failed '%s'", 396465e1141STomohiro Kusumi h2_opt->inode_cmd_name, image, 397465e1141STomohiro Kusumi strerror(error)); 398465e1141STomohiro Kusumi } else if (!strcmp(h2_opt->inode_cmd_name, "setcomp")) { 399465e1141STomohiro Kusumi error = hammer2_inode_setcomp(vroot, 400465e1141STomohiro Kusumi h2_opt->inode_path); 401465e1141STomohiro Kusumi if (error) 402465e1141STomohiro Kusumi errx(1, "inode %s `%s' failed '%s'", 403465e1141STomohiro Kusumi h2_opt->inode_cmd_name, image, 404465e1141STomohiro Kusumi strerror(error)); 405465e1141STomohiro Kusumi } else { 406465e1141STomohiro Kusumi assert(0); 407465e1141STomohiro Kusumi } 408465e1141STomohiro Kusumi TIMER_RESULTS(start, "hammer2_inode_setx"); 409465e1141STomohiro Kusumi break; 4109a149651STomohiro Kusumi case HAMMER2IOC_BULKFREE_SCAN: 411a63188c8STomohiro Kusumi printf("bulkfree `%s'\n", image); 412a63188c8STomohiro Kusumi TIMER_START(start); 41306d1ac82STomohiro Kusumi error = hammer2_bulkfree(vroot); 41406d1ac82STomohiro Kusumi if (error) 41506d1ac82STomohiro Kusumi errx(1, "bulkfree `%s' failed '%s'", image, 41606d1ac82STomohiro Kusumi strerror(error)); 417a63188c8STomohiro Kusumi TIMER_RESULTS(start, "hammer2_bulkfree"); 4189a149651STomohiro Kusumi break; 4199a149651STomohiro Kusumi case HAMMER2IOC_DESTROY: 420917508cdSTomohiro Kusumi TIMER_START(start); 421917508cdSTomohiro Kusumi if (strlen(h2_opt->destroy_path)) { 422917508cdSTomohiro Kusumi printf("destroy `%s' in `%s'\n", 423917508cdSTomohiro Kusumi h2_opt->destroy_path, image); 42406d1ac82STomohiro Kusumi error = hammer2_destroy_path(vroot, 42506d1ac82STomohiro Kusumi h2_opt->destroy_path); 42606d1ac82STomohiro Kusumi if (error) 42706d1ac82STomohiro Kusumi errx(1, "destroy `%s' in `%s' failed '%s'", 42806d1ac82STomohiro Kusumi h2_opt->destroy_path, image, 42906d1ac82STomohiro Kusumi strerror(error)); 430917508cdSTomohiro Kusumi } else { 431917508cdSTomohiro Kusumi printf("destroy %lld in `%s'\n", 432917508cdSTomohiro Kusumi (long long)h2_opt->destroy_inum, image); 43306d1ac82STomohiro Kusumi error = hammer2_destroy_inum(vroot, 43406d1ac82STomohiro Kusumi h2_opt->destroy_inum); 43506d1ac82STomohiro Kusumi if (error) 43606d1ac82STomohiro Kusumi errx(1, "destroy %lld in `%s' failed '%s'", 43706d1ac82STomohiro Kusumi (long long)h2_opt->destroy_inum, image, 43806d1ac82STomohiro Kusumi strerror(error)); 439917508cdSTomohiro Kusumi } 440917508cdSTomohiro Kusumi TIMER_RESULTS(start, "hammer2_destroy"); 4419a149651STomohiro Kusumi break; 4429a149651STomohiro Kusumi case HAMMER2IOC_GROWFS: 443afa5234bSTomohiro Kusumi printf("growfs `%s'\n", image); 444afa5234bSTomohiro Kusumi TIMER_START(start); 44506d1ac82STomohiro Kusumi error = hammer2_growfs(vroot, h2_opt->image_size); 44606d1ac82STomohiro Kusumi if (error) 44706d1ac82STomohiro Kusumi errx(1, "growfs `%s' failed '%s'", image, 44806d1ac82STomohiro Kusumi strerror(error)); 449afa5234bSTomohiro Kusumi TIMER_RESULTS(start, "hammer2_growfs"); 4509a149651STomohiro Kusumi break; 4519a149651STomohiro Kusumi default: 452b4807901STomohiro Kusumi printf("populating `%s'\n", image); 453b4807901STomohiro Kusumi TIMER_START(start); 454b4807901STomohiro Kusumi if (hammer2_populate_dir(vroot, dir, root, root, fsopts, 0)) 455b4807901STomohiro Kusumi errx(1, "image file `%s' not populated", image); 456b4807901STomohiro Kusumi TIMER_RESULTS(start, "hammer2_populate_dir"); 4579a149651STomohiro Kusumi break; 458a63188c8STomohiro Kusumi } 4592d60b848STomohiro Kusumi 4602d60b848STomohiro Kusumi /* unmount image */ 4612d60b848STomohiro Kusumi error = hammer2_vfs_unmount(&mp, 0); 4622d60b848STomohiro Kusumi if (error) 4632d60b848STomohiro Kusumi errx(1, "failed to unmount, error %d", error); 4642d60b848STomohiro Kusumi 4652d60b848STomohiro Kusumi /* check leaked resource */ 4662d60b848STomohiro Kusumi if (vnode_count) 467f8a1147cSTomohiro Kusumi printf("XXX %lld vnode left\n", (long long)vnode_count); 4682d60b848STomohiro Kusumi if (hammer2_chain_allocs) 4692d60b848STomohiro Kusumi printf("XXX %ld chain left\n", hammer2_chain_allocs); 4702d60b848STomohiro Kusumi bcleanup(); 4712d60b848STomohiro Kusumi 4722d60b848STomohiro Kusumi /* vfs uninit */ 4732d60b848STomohiro Kusumi error = hammer2_vfs_uninit(); 4742d60b848STomohiro Kusumi if (error) 4752d60b848STomohiro Kusumi errx(1, "failed to vfs uninit, error %d", error); 4762d60b848STomohiro Kusumi 4772d60b848STomohiro Kusumi if (close(fsopts->fd) == -1) 4782d60b848STomohiro Kusumi err(1, "closing `%s'", image); 4792d60b848STomohiro Kusumi fsopts->fd = -1; 4802d60b848STomohiro Kusumi 4812d60b848STomohiro Kusumi printf("image `%s' complete\n", image); 4822d60b848STomohiro Kusumi } 4832d60b848STomohiro Kusumi 4842d60b848STomohiro Kusumi /* end of public functions */ 4852d60b848STomohiro Kusumi 4863999233bSTomohiro Kusumi static void 4873999233bSTomohiro Kusumi hammer2_parse_pfs_opts(const char *buf, fsinfo_t *fsopts) 4883999233bSTomohiro Kusumi { 4893999233bSTomohiro Kusumi hammer2_makefs_options_t *h2_opt = fsopts->fs_specific; 4903999233bSTomohiro Kusumi char *o, *p; 4913999233bSTomohiro Kusumi size_t n; 4923999233bSTomohiro Kusumi 4933999233bSTomohiro Kusumi o = p = strdup(buf); 4943999233bSTomohiro Kusumi p = strchr(p, ':'); 4953999233bSTomohiro Kusumi if (p != NULL) { 4963999233bSTomohiro Kusumi *p++ = 0; 4973999233bSTomohiro Kusumi n = strlen(p); 4983999233bSTomohiro Kusumi } else { 4993999233bSTomohiro Kusumi n = 0; 5003999233bSTomohiro Kusumi } 5013999233bSTomohiro Kusumi 5023999233bSTomohiro Kusumi if (!strcmp(o, "get") || !strcmp(o, "list")) { 5039a149651STomohiro Kusumi h2_opt->ioctl_cmd = HAMMER2IOC_PFS_GET; 5043999233bSTomohiro Kusumi } else if (!strcmp(o, "lookup")) { 5053999233bSTomohiro Kusumi if (n == 0 || n > NAME_MAX) 5063999233bSTomohiro Kusumi errx(1, "invalid PFS name \"%s\"", p); 5079a149651STomohiro Kusumi h2_opt->ioctl_cmd = HAMMER2IOC_PFS_LOOKUP; 5083999233bSTomohiro Kusumi } else if (!strcmp(o, "create")) { 5093999233bSTomohiro Kusumi if (n == 0 || n > NAME_MAX) 5103999233bSTomohiro Kusumi errx(1, "invalid PFS name \"%s\"", p); 5119a149651STomohiro Kusumi h2_opt->ioctl_cmd = HAMMER2IOC_PFS_CREATE; 5123999233bSTomohiro Kusumi } else if (!strcmp(o, "delete")) { 5133999233bSTomohiro Kusumi if (n == 0 || n > NAME_MAX) 5143999233bSTomohiro Kusumi errx(1, "invalid PFS name \"%s\"", p); 5159a149651STomohiro Kusumi h2_opt->ioctl_cmd = HAMMER2IOC_PFS_DELETE; 5163999233bSTomohiro Kusumi } else if (!strcmp(o, "snapshot")) { 5173999233bSTomohiro Kusumi if (n > NAME_MAX) 5183999233bSTomohiro Kusumi errx(1, "invalid PFS name \"%s\"", p); 5199a149651STomohiro Kusumi h2_opt->ioctl_cmd = HAMMER2IOC_PFS_SNAPSHOT; 5203999233bSTomohiro Kusumi } else { 5213999233bSTomohiro Kusumi errx(1, "invalid PFS command \"%s\"", o); 5223999233bSTomohiro Kusumi } 5233999233bSTomohiro Kusumi 5243999233bSTomohiro Kusumi strlcpy(h2_opt->pfs_cmd_name, o, sizeof(h2_opt->pfs_cmd_name)); 5253999233bSTomohiro Kusumi if (n > 0) 5263999233bSTomohiro Kusumi strlcpy(h2_opt->pfs_name, p, sizeof(h2_opt->pfs_name)); 5273999233bSTomohiro Kusumi 5283999233bSTomohiro Kusumi free(o); 5293999233bSTomohiro Kusumi } 5303999233bSTomohiro Kusumi 531f804c425STomohiro Kusumi static void 532f804c425STomohiro Kusumi hammer2_parse_inode_opts(const char *buf, fsinfo_t *fsopts) 533f804c425STomohiro Kusumi { 534f804c425STomohiro Kusumi hammer2_makefs_options_t *h2_opt = fsopts->fs_specific; 535f804c425STomohiro Kusumi char *o, *p; 536f804c425STomohiro Kusumi size_t n; 537f804c425STomohiro Kusumi 538f804c425STomohiro Kusumi o = p = strdup(buf); 539f804c425STomohiro Kusumi p = strchr(p, ':'); 540f804c425STomohiro Kusumi if (p != NULL) { 541f804c425STomohiro Kusumi *p++ = 0; 542f804c425STomohiro Kusumi n = strlen(p); 543f804c425STomohiro Kusumi } else { 544f804c425STomohiro Kusumi n = 0; 545f804c425STomohiro Kusumi } 546f804c425STomohiro Kusumi 547f804c425STomohiro Kusumi if (!strcmp(o, "get")) { 548f804c425STomohiro Kusumi if (n == 0 || n > PATH_MAX) 549f804c425STomohiro Kusumi errx(1, "invalid file path \"%s\"", p); 550f804c425STomohiro Kusumi h2_opt->ioctl_cmd = HAMMER2IOC_INODE_GET; 551465e1141STomohiro Kusumi } else if (!strcmp(o, "setcheck")) { 552465e1141STomohiro Kusumi if (n == 0 || n > PATH_MAX - 10) 553465e1141STomohiro Kusumi errx(1, "invalid argument \"%s\"", p); 554465e1141STomohiro Kusumi h2_opt->ioctl_cmd = HAMMER2IOC_INODE_SET; 555465e1141STomohiro Kusumi } else if (!strcmp(o, "setcomp")) { 556465e1141STomohiro Kusumi if (n == 0 || n > PATH_MAX - 10) 557465e1141STomohiro Kusumi errx(1, "invalid argument \"%s\"", p); 558465e1141STomohiro Kusumi h2_opt->ioctl_cmd = HAMMER2IOC_INODE_SET; 559f804c425STomohiro Kusumi } else { 560f804c425STomohiro Kusumi errx(1, "invalid inode command \"%s\"", o); 561f804c425STomohiro Kusumi } 562f804c425STomohiro Kusumi 563465e1141STomohiro Kusumi strlcpy(h2_opt->inode_cmd_name, o, sizeof(h2_opt->inode_cmd_name)); 5646857f034STomohiro Kusumi if (n > 0) 565f804c425STomohiro Kusumi strlcpy(h2_opt->inode_path, p, sizeof(h2_opt->inode_path)); 566f804c425STomohiro Kusumi 567f804c425STomohiro Kusumi free(o); 568f804c425STomohiro Kusumi } 569f804c425STomohiro Kusumi 5702d60b848STomohiro Kusumi static hammer2_off_t 5712d60b848STomohiro Kusumi hammer2_image_size(fsinfo_t *fsopts) 5722d60b848STomohiro Kusumi { 5732d60b848STomohiro Kusumi hammer2_makefs_options_t *h2_opt = fsopts->fs_specific; 5742d60b848STomohiro Kusumi hammer2_off_t image_size, used_size = 0; 5752d60b848STomohiro Kusumi int num_level1, delta_num_level1; 5762d60b848STomohiro Kusumi 5772d60b848STomohiro Kusumi /* use 4 volume headers by default */ 5782d60b848STomohiro Kusumi num_level1 = h2_opt->num_volhdr * 2; /* default 4 x 2 */ 5792d60b848STomohiro Kusumi assert(num_level1 != 0); 5802d60b848STomohiro Kusumi assert(num_level1 <= 8); 5812d60b848STomohiro Kusumi 5822d60b848STomohiro Kusumi /* add 4MiB segment for each level1 */ 5832d60b848STomohiro Kusumi used_size += HAMMER2_ZONE_SEG64 * num_level1; 5842d60b848STomohiro Kusumi 5852d60b848STomohiro Kusumi /* add boot/aux area, but exact size unknown at this point */ 5862d60b848STomohiro Kusumi used_size += HAMMER2_BOOT_NOM_BYTES + HAMMER2_AUX_NOM_BYTES; 5872d60b848STomohiro Kusumi 5882d60b848STomohiro Kusumi /* add data size */ 5892d60b848STomohiro Kusumi used_size += fsopts->size; 5902d60b848STomohiro Kusumi 5912d60b848STomohiro Kusumi /* XXX add extra level1 for meta data and indirect blocks */ 5922d60b848STomohiro Kusumi used_size += HAMMER2_FREEMAP_LEVEL1_SIZE; 5932d60b848STomohiro Kusumi 5942d60b848STomohiro Kusumi /* XXX add extra level1 for safety */ 5952d60b848STomohiro Kusumi if (used_size > HAMMER2_FREEMAP_LEVEL1_SIZE * 10) 5962d60b848STomohiro Kusumi used_size += HAMMER2_FREEMAP_LEVEL1_SIZE; 5972d60b848STomohiro Kusumi 5982d60b848STomohiro Kusumi /* use 8GiB image size by default */ 5992d60b848STomohiro Kusumi image_size = HAMMER2_FREEMAP_LEVEL1_SIZE * num_level1; 6002d60b848STomohiro Kusumi printf("trying default image size %s\n", sizetostr(image_size)); 6012d60b848STomohiro Kusumi 6022d60b848STomohiro Kusumi /* adjust if image size isn't large enough */ 6032d60b848STomohiro Kusumi if (used_size > image_size) { 6042d60b848STomohiro Kusumi /* determine extra level1 needed */ 6052d60b848STomohiro Kusumi delta_num_level1 = howmany(used_size - image_size, 6062d60b848STomohiro Kusumi HAMMER2_FREEMAP_LEVEL1_SIZE); 6072d60b848STomohiro Kusumi 6082d60b848STomohiro Kusumi /* adjust used size with 4MiB segment for each extra level1 */ 6092d60b848STomohiro Kusumi used_size += HAMMER2_ZONE_SEG64 * delta_num_level1; 6102d60b848STomohiro Kusumi 6112d60b848STomohiro Kusumi /* adjust image size with extra level1 */ 6122d60b848STomohiro Kusumi image_size += HAMMER2_FREEMAP_LEVEL1_SIZE * delta_num_level1; 6132d60b848STomohiro Kusumi printf("trying adjusted image size %s\n", 6142d60b848STomohiro Kusumi sizetostr(image_size)); 6152d60b848STomohiro Kusumi 6162d60b848STomohiro Kusumi if (used_size > image_size) 617f8a1147cSTomohiro Kusumi errx(1, "invalid used_size %lld > image_size %lld", 618f8a1147cSTomohiro Kusumi (long long)used_size, (long long)image_size); 6192d60b848STomohiro Kusumi } 6202d60b848STomohiro Kusumi 6212d60b848STomohiro Kusumi return image_size; 6222d60b848STomohiro Kusumi } 6232d60b848STomohiro Kusumi 6242d60b848STomohiro Kusumi static const char * 6252d60b848STomohiro Kusumi hammer2_label_name(int label_type) 6262d60b848STomohiro Kusumi { 6272d60b848STomohiro Kusumi switch (label_type) { 6282d60b848STomohiro Kusumi case HAMMER2_LABEL_NONE: 6292d60b848STomohiro Kusumi return "NONE"; 6302d60b848STomohiro Kusumi case HAMMER2_LABEL_BOOT: 6312d60b848STomohiro Kusumi return "BOOT"; 6322d60b848STomohiro Kusumi case HAMMER2_LABEL_ROOT: 6332d60b848STomohiro Kusumi return "ROOT"; 6342d60b848STomohiro Kusumi case HAMMER2_LABEL_DATA: 6352d60b848STomohiro Kusumi return "DATA"; 6362d60b848STomohiro Kusumi default: 6372d60b848STomohiro Kusumi assert(0); 6382d60b848STomohiro Kusumi } 6392d60b848STomohiro Kusumi return NULL; 6402d60b848STomohiro Kusumi } 6412d60b848STomohiro Kusumi 6422d60b848STomohiro Kusumi static void 6432d60b848STomohiro Kusumi hammer2_validate(const char *dir, fsnode *root, fsinfo_t *fsopts) 6442d60b848STomohiro Kusumi { 6452d60b848STomohiro Kusumi hammer2_makefs_options_t *h2_opt = fsopts->fs_specific; 6462d60b848STomohiro Kusumi hammer2_mkfs_options_t *opt = &h2_opt->mkfs_options; 647afa5234bSTomohiro Kusumi hammer2_off_t image_size = 0, minsize, maxsize; 6482d60b848STomohiro Kusumi const char *s; 6492d60b848STomohiro Kusumi 65070e962f7STomohiro Kusumi /* ioctl commands could have NULL dir / root */ 6512d60b848STomohiro Kusumi assert(fsopts != NULL); 6522d60b848STomohiro Kusumi 6532d60b848STomohiro Kusumi if (debug & DEBUG_FS_VALIDATE) { 6542d60b848STomohiro Kusumi APRINTF("before defaults set:\n"); 6552d60b848STomohiro Kusumi hammer2_dump_fsinfo(fsopts); 6562d60b848STomohiro Kusumi } 6572d60b848STomohiro Kusumi 6582d60b848STomohiro Kusumi /* makefs only supports "DATA" for default PFS label */ 6592d60b848STomohiro Kusumi if (!h2_opt->label_specified) { 6602d60b848STomohiro Kusumi opt->DefaultLabelType = HAMMER2_LABEL_DATA; 6612d60b848STomohiro Kusumi s = hammer2_label_name(opt->DefaultLabelType); 6622d60b848STomohiro Kusumi printf("using default label \"%s\"\n", s); 6632d60b848STomohiro Kusumi } 6642d60b848STomohiro Kusumi 6652d60b848STomohiro Kusumi /* set default mount PFS label */ 6662d60b848STomohiro Kusumi if (!strcmp(h2_opt->mount_label, "")) { 6672d60b848STomohiro Kusumi s = hammer2_label_name(HAMMER2_LABEL_DATA); 6682d60b848STomohiro Kusumi strlcpy(h2_opt->mount_label, s, sizeof(h2_opt->mount_label)); 6692d60b848STomohiro Kusumi printf("using default mount label \"%s\"\n", s); 6702d60b848STomohiro Kusumi } 6712d60b848STomohiro Kusumi 6722d60b848STomohiro Kusumi /* set default number of volume headers */ 6732d60b848STomohiro Kusumi if (!h2_opt->num_volhdr) { 6742d60b848STomohiro Kusumi h2_opt->num_volhdr = HAMMER2_NUM_VOLHDRS; 6752d60b848STomohiro Kusumi printf("using default %d volume headers\n", h2_opt->num_volhdr); 6762d60b848STomohiro Kusumi } 6772d60b848STomohiro Kusumi 678917508cdSTomohiro Kusumi /* done if ioctl commands */ 6799a149651STomohiro Kusumi if (h2_opt->ioctl_cmd) { 6809a149651STomohiro Kusumi if (h2_opt->ioctl_cmd == HAMMER2IOC_GROWFS) 681afa5234bSTomohiro Kusumi goto ignore_size_dir; 6829a149651STomohiro Kusumi else 6839a149651STomohiro Kusumi goto done; 6849a149651STomohiro Kusumi } 685a63188c8STomohiro Kusumi 6862d60b848STomohiro Kusumi /* calculate data size */ 6872d60b848STomohiro Kusumi if (fsopts->size != 0) 6882d60b848STomohiro Kusumi fsopts->size = 0; /* shouldn't reach here to begin with */ 689a63188c8STomohiro Kusumi if (root == NULL) 690a63188c8STomohiro Kusumi errx(1, "fsnode tree not constructed"); 6912d60b848STomohiro Kusumi hammer2_size_dir(root, fsopts); 6922d60b848STomohiro Kusumi printf("estimated data size %s from %lld inode\n", 6932d60b848STomohiro Kusumi sizetostr(fsopts->size), (long long)fsopts->inodes); 6942d60b848STomohiro Kusumi 6952d60b848STomohiro Kusumi /* determine image size from data size */ 6962d60b848STomohiro Kusumi image_size = hammer2_image_size(fsopts); 6972d60b848STomohiro Kusumi assert((image_size & HAMMER2_FREEMAP_LEVEL1_MASK) == 0); 698afa5234bSTomohiro Kusumi ignore_size_dir: 6992d60b848STomohiro Kusumi minsize = roundup(fsopts->minsize, HAMMER2_FREEMAP_LEVEL1_SIZE); 7002d60b848STomohiro Kusumi maxsize = roundup(fsopts->maxsize, HAMMER2_FREEMAP_LEVEL1_SIZE); 7012d60b848STomohiro Kusumi if (image_size < minsize) 7022d60b848STomohiro Kusumi image_size = minsize; 7032d60b848STomohiro Kusumi else if (maxsize > 0 && image_size > maxsize) 704f8a1147cSTomohiro Kusumi errx(1, "`%s' size of %lld is larger than the maxsize of %lld", 705f8a1147cSTomohiro Kusumi dir, (long long)image_size, (long long)maxsize); 7062d60b848STomohiro Kusumi 7072d60b848STomohiro Kusumi assert((image_size & HAMMER2_FREEMAP_LEVEL1_MASK) == 0); 7082d60b848STomohiro Kusumi h2_opt->image_size = image_size; 7092d60b848STomohiro Kusumi printf("using %s image size\n", sizetostr(h2_opt->image_size)); 710a63188c8STomohiro Kusumi done: 7112d60b848STomohiro Kusumi if (debug & DEBUG_FS_VALIDATE) { 7122d60b848STomohiro Kusumi APRINTF("after defaults set:\n"); 7132d60b848STomohiro Kusumi hammer2_dump_fsinfo(fsopts); 7142d60b848STomohiro Kusumi } 7152d60b848STomohiro Kusumi } 7162d60b848STomohiro Kusumi 7172d60b848STomohiro Kusumi static void 7182d60b848STomohiro Kusumi hammer2_dump_fsinfo(fsinfo_t *fsopts) 7192d60b848STomohiro Kusumi { 7202d60b848STomohiro Kusumi hammer2_makefs_options_t *h2_opt = fsopts->fs_specific; 7212d60b848STomohiro Kusumi hammer2_mkfs_options_t *opt = &h2_opt->mkfs_options; 7222d60b848STomohiro Kusumi int i; 7232d60b848STomohiro Kusumi char *s; 7242d60b848STomohiro Kusumi 7252d60b848STomohiro Kusumi assert(fsopts != NULL); 7262d60b848STomohiro Kusumi 7272d60b848STomohiro Kusumi APRINTF("fsinfo_t at %p\n", fsopts); 7282d60b848STomohiro Kusumi 7292d60b848STomohiro Kusumi printf("\tinodes %lld\n", (long long)fsopts->inodes); 7302d60b848STomohiro Kusumi printf("\tsize %lld, minsize %lld, maxsize %lld\n", 7312d60b848STomohiro Kusumi (long long)fsopts->size, 7322d60b848STomohiro Kusumi (long long)fsopts->minsize, 7332d60b848STomohiro Kusumi (long long)fsopts->maxsize); 7342d60b848STomohiro Kusumi 7352d60b848STomohiro Kusumi printf("\thammer2_debug 0x%x\n", hammer2_debug); 7362d60b848STomohiro Kusumi 7372d60b848STomohiro Kusumi printf("\tlabel_specified %d\n", h2_opt->label_specified); 7382d60b848STomohiro Kusumi printf("\tmount_label \"%s\"\n", h2_opt->mount_label); 7392d60b848STomohiro Kusumi printf("\tnum_volhdr %d\n", h2_opt->num_volhdr); 7409a149651STomohiro Kusumi printf("\tioctl_cmd %ld\n", h2_opt->ioctl_cmd); 74148ed4577STomohiro Kusumi printf("\temergency_mode %d\n", h2_opt->emergency_mode); 7423999233bSTomohiro Kusumi printf("\tpfs_cmd_name \"%s\"\n", h2_opt->pfs_cmd_name); 7433999233bSTomohiro Kusumi printf("\tpfs_name \"%s\"\n", h2_opt->pfs_name); 744465e1141STomohiro Kusumi printf("\tinode_cmd_name \"%s\"\n", h2_opt->inode_cmd_name); 745f804c425STomohiro Kusumi printf("\tinode_path \"%s\"\n", h2_opt->inode_path); 746917508cdSTomohiro Kusumi printf("\tdestroy_path \"%s\"\n", h2_opt->destroy_path); 747917508cdSTomohiro Kusumi printf("\tdestroy_inum %lld\n", (long long)h2_opt->destroy_inum); 748f8a1147cSTomohiro Kusumi printf("\timage_size 0x%llx\n", (long long)h2_opt->image_size); 7492d60b848STomohiro Kusumi 7502d60b848STomohiro Kusumi printf("\tHammer2Version %d\n", opt->Hammer2Version); 7512d60b848STomohiro Kusumi printf("\tBootAreaSize 0x%jx\n", opt->BootAreaSize); 7522d60b848STomohiro Kusumi printf("\tAuxAreaSize 0x%jx\n", opt->AuxAreaSize); 7532d60b848STomohiro Kusumi printf("\tNLabels %d\n", opt->NLabels); 7542d60b848STomohiro Kusumi printf("\tCompType %d\n", opt->CompType); 7552d60b848STomohiro Kusumi printf("\tCheckType %d\n", opt->CheckType); 7562d60b848STomohiro Kusumi printf("\tDefaultLabelType %d\n", opt->DefaultLabelType); 7572d60b848STomohiro Kusumi printf("\tDebugOpt %d\n", opt->DebugOpt); 7582d60b848STomohiro Kusumi 7592d60b848STomohiro Kusumi s = NULL; 7602d60b848STomohiro Kusumi hammer2_uuid_to_str(&opt->Hammer2_FSType, &s); 7612d60b848STomohiro Kusumi printf("\tHammer2_FSType \"%s\"\n", s); 7622d60b848STomohiro Kusumi s = NULL; 7632d60b848STomohiro Kusumi hammer2_uuid_to_str(&opt->Hammer2_VolFSID, &s); 7642d60b848STomohiro Kusumi printf("\tHammer2_VolFSID \"%s\"\n", s); 7652d60b848STomohiro Kusumi s = NULL; 7662d60b848STomohiro Kusumi hammer2_uuid_to_str(&opt->Hammer2_SupCLID, &s); 7672d60b848STomohiro Kusumi printf("\tHammer2_SupCLID \"%s\"\n", s); 7682d60b848STomohiro Kusumi s = NULL; 7692d60b848STomohiro Kusumi hammer2_uuid_to_str(&opt->Hammer2_SupFSID, &s); 7702d60b848STomohiro Kusumi printf("\tHammer2_SupFSID \"%s\"\n", s); 7712d60b848STomohiro Kusumi 7722d60b848STomohiro Kusumi for (i = 0; i < opt->NLabels; i++) { 7732d60b848STomohiro Kusumi printf("\tLabel[%d] \"%s\"\n", i, opt->Label[i]); 7742d60b848STomohiro Kusumi s = NULL; 7752d60b848STomohiro Kusumi hammer2_uuid_to_str(&opt->Hammer2_PfsCLID[i], &s); 7762d60b848STomohiro Kusumi printf("\t Hammer2_PfsCLID[%d] \"%s\"\n", i, s); 7772d60b848STomohiro Kusumi s = NULL; 7782d60b848STomohiro Kusumi hammer2_uuid_to_str(&opt->Hammer2_PfsFSID[i], &s); 7792d60b848STomohiro Kusumi printf("\t Hammer2_PfsFSID[%d] \"%s\"\n", i, s); 7802d60b848STomohiro Kusumi } 7812d60b848STomohiro Kusumi 7822d60b848STomohiro Kusumi free(s); 7832d60b848STomohiro Kusumi } 7842d60b848STomohiro Kusumi 7852d60b848STomohiro Kusumi static int 7862d60b848STomohiro Kusumi hammer2_create_image(const char *image, fsinfo_t *fsopts) 7872d60b848STomohiro Kusumi { 7882d60b848STomohiro Kusumi hammer2_makefs_options_t *h2_opt = fsopts->fs_specific; 7892d60b848STomohiro Kusumi hammer2_mkfs_options_t *opt = &h2_opt->mkfs_options; 7902d60b848STomohiro Kusumi char *av[] = { (char *)image, }; /* XXX support multi-volumes */ 7912d60b848STomohiro Kusumi char *buf; 7922d60b848STomohiro Kusumi int i, bufsize, oflags; 7932d60b848STomohiro Kusumi off_t bufrem; 7942d60b848STomohiro Kusumi 7952d60b848STomohiro Kusumi assert(image != NULL); 7962d60b848STomohiro Kusumi assert(fsopts != NULL); 7972d60b848STomohiro Kusumi 7982d60b848STomohiro Kusumi /* create image */ 7992d60b848STomohiro Kusumi oflags = O_RDWR | O_CREAT; 8002d60b848STomohiro Kusumi if (fsopts->offset == 0) 8012d60b848STomohiro Kusumi oflags |= O_TRUNC; 8022d60b848STomohiro Kusumi if ((fsopts->fd = open(image, oflags, 0666)) == -1) { 8032d60b848STomohiro Kusumi warn("can't open `%s' for writing", image); 8042d60b848STomohiro Kusumi return -1; 8052d60b848STomohiro Kusumi } 8062d60b848STomohiro Kusumi 8072d60b848STomohiro Kusumi /* zero image */ 8082d60b848STomohiro Kusumi bufsize = HAMMER2_PBUFSIZE; 8092d60b848STomohiro Kusumi bufrem = h2_opt->image_size; 8102d60b848STomohiro Kusumi if (fsopts->sparse) { 8112d60b848STomohiro Kusumi if (ftruncate(fsopts->fd, bufrem) == -1) { 8122d60b848STomohiro Kusumi warn("sparse option disabled"); 8132d60b848STomohiro Kusumi fsopts->sparse = 0; 8142d60b848STomohiro Kusumi } 8152d60b848STomohiro Kusumi } 8162d60b848STomohiro Kusumi if (fsopts->sparse) { 8172d60b848STomohiro Kusumi /* File truncated at bufrem. Remaining is 0 */ 8182d60b848STomohiro Kusumi bufrem = 0; 8192d60b848STomohiro Kusumi buf = NULL; 8202d60b848STomohiro Kusumi } else { 8212d60b848STomohiro Kusumi if (debug & DEBUG_FS_CREATE_IMAGE) 8222d60b848STomohiro Kusumi APRINTF("zero-ing image `%s', %lld sectors, " 8232d60b848STomohiro Kusumi "using %d byte chunks\n", 8242d60b848STomohiro Kusumi image, (long long)bufrem, bufsize); 8252d60b848STomohiro Kusumi buf = ecalloc(1, bufsize); 8262d60b848STomohiro Kusumi } 8272d60b848STomohiro Kusumi 8282d60b848STomohiro Kusumi if (fsopts->offset != 0) { 8292d60b848STomohiro Kusumi if (lseek(fsopts->fd, fsopts->offset, SEEK_SET) == -1) { 8302d60b848STomohiro Kusumi warn("can't seek"); 8312d60b848STomohiro Kusumi free(buf); 8322d60b848STomohiro Kusumi return -1; 8332d60b848STomohiro Kusumi } 8342d60b848STomohiro Kusumi } 8352d60b848STomohiro Kusumi 8362d60b848STomohiro Kusumi while (bufrem > 0) { 8372d60b848STomohiro Kusumi i = write(fsopts->fd, buf, MIN(bufsize, bufrem)); 8382d60b848STomohiro Kusumi if (i == -1) { 8392d60b848STomohiro Kusumi warn("zeroing image, %lld bytes to go", 8402d60b848STomohiro Kusumi (long long)bufrem); 8412d60b848STomohiro Kusumi free(buf); 8422d60b848STomohiro Kusumi return -1; 8432d60b848STomohiro Kusumi } 8442d60b848STomohiro Kusumi bufrem -= i; 8452d60b848STomohiro Kusumi } 8462d60b848STomohiro Kusumi if (buf) 8472d60b848STomohiro Kusumi free(buf); 8482d60b848STomohiro Kusumi 8492d60b848STomohiro Kusumi /* make the file system */ 8502d60b848STomohiro Kusumi if (debug & DEBUG_FS_CREATE_IMAGE) 8512d60b848STomohiro Kusumi APRINTF("calling mkfs(\"%s\", ...)\n", image); 8522d60b848STomohiro Kusumi hammer2_mkfs(1, av, opt); /* success if returned */ 8532d60b848STomohiro Kusumi 8542d60b848STomohiro Kusumi return fsopts->fd; 8552d60b848STomohiro Kusumi } 8562d60b848STomohiro Kusumi 8572d60b848STomohiro Kusumi static off_t 8582d60b848STomohiro Kusumi hammer2_phys_size(off_t size) 8592d60b848STomohiro Kusumi { 8602d60b848STomohiro Kusumi off_t radix_size, phys_size = 0; 8612d60b848STomohiro Kusumi int i; 8622d60b848STomohiro Kusumi 8632d60b848STomohiro Kusumi if (size > HAMMER2_PBUFSIZE) { 8642d60b848STomohiro Kusumi phys_size += rounddown(size, HAMMER2_PBUFSIZE); 8652d60b848STomohiro Kusumi size = size % HAMMER2_PBUFSIZE; 8662d60b848STomohiro Kusumi } 8672d60b848STomohiro Kusumi 8682d60b848STomohiro Kusumi for (i = HAMMER2_RADIX_MIN; i <= HAMMER2_RADIX_MAX; i++) { 8692d60b848STomohiro Kusumi radix_size = 1UL << i; 8702d60b848STomohiro Kusumi if (radix_size >= size) { 8712d60b848STomohiro Kusumi phys_size += radix_size; 8722d60b848STomohiro Kusumi break; 8732d60b848STomohiro Kusumi } 8742d60b848STomohiro Kusumi } 8752d60b848STomohiro Kusumi 8762d60b848STomohiro Kusumi return phys_size; 8772d60b848STomohiro Kusumi } 8782d60b848STomohiro Kusumi 8792d60b848STomohiro Kusumi /* calculate data size */ 8802d60b848STomohiro Kusumi static void 8812d60b848STomohiro Kusumi hammer2_size_dir(fsnode *root, fsinfo_t *fsopts) 8822d60b848STomohiro Kusumi { 8832d60b848STomohiro Kusumi fsnode *node; 8842d60b848STomohiro Kusumi 8852d60b848STomohiro Kusumi assert(fsopts != NULL); 8862d60b848STomohiro Kusumi 8872d60b848STomohiro Kusumi if (debug & DEBUG_FS_SIZE_DIR) 8882d60b848STomohiro Kusumi APRINTF("entry: bytes %lld inodes %lld\n", 8892d60b848STomohiro Kusumi (long long)fsopts->size, (long long)fsopts->inodes); 8902d60b848STomohiro Kusumi 8912d60b848STomohiro Kusumi for (node = root; node != NULL; node = node->next) { 8922d60b848STomohiro Kusumi if (node == root) { /* we're at "." */ 8932d60b848STomohiro Kusumi assert(strcmp(node->name, ".") == 0); 8942d60b848STomohiro Kusumi } else if ((node->inode->flags & FI_SIZED) == 0) { 8952d60b848STomohiro Kusumi /* don't count duplicate names */ 8962d60b848STomohiro Kusumi node->inode->flags |= FI_SIZED; 8972d60b848STomohiro Kusumi if (debug & DEBUG_FS_SIZE_DIR_NODE) 8982d60b848STomohiro Kusumi APRINTF("`%s' size %lld\n", 8992d60b848STomohiro Kusumi node->name, 9002d60b848STomohiro Kusumi (long long)node->inode->st.st_size); 9012d60b848STomohiro Kusumi fsopts->inodes++; 9022d60b848STomohiro Kusumi fsopts->size += sizeof(hammer2_inode_data_t); 9032d60b848STomohiro Kusumi if (node->type == S_IFREG) { 9042d60b848STomohiro Kusumi size_t st_size = node->inode->st.st_size; 9052d60b848STomohiro Kusumi if (st_size > HAMMER2_EMBEDDED_BYTES) 9062d60b848STomohiro Kusumi fsopts->size += hammer2_phys_size(st_size); 9072d60b848STomohiro Kusumi } else if (node->type == S_IFLNK) { 9082d60b848STomohiro Kusumi size_t nlen = strlen(node->symlink); 9092d60b848STomohiro Kusumi if (nlen > HAMMER2_EMBEDDED_BYTES) 9102d60b848STomohiro Kusumi fsopts->size += hammer2_phys_size(nlen); 9112d60b848STomohiro Kusumi } 9122d60b848STomohiro Kusumi } 9132d60b848STomohiro Kusumi if (node->type == S_IFDIR) 9142d60b848STomohiro Kusumi hammer2_size_dir(node->child, fsopts); 9152d60b848STomohiro Kusumi } 9162d60b848STomohiro Kusumi 9172d60b848STomohiro Kusumi if (debug & DEBUG_FS_SIZE_DIR) 9182d60b848STomohiro Kusumi APRINTF("exit: size %lld inodes %lld\n", 9192d60b848STomohiro Kusumi (long long)fsopts->size, (long long)fsopts->inodes); 9202d60b848STomohiro Kusumi } 9212d60b848STomohiro Kusumi 9222d60b848STomohiro Kusumi static void 9236bcbb706STomohiro Kusumi hammer2_print(const struct m_vnode *dvp, const struct m_vnode *vp, 9242d60b848STomohiro Kusumi const fsnode *node, int depth, const char *msg) 9252d60b848STomohiro Kusumi { 9262d60b848STomohiro Kusumi if (debug & DEBUG_FS_POPULATE) { 9272d60b848STomohiro Kusumi if (1) { 9282d60b848STomohiro Kusumi int indent = depth * 2; 9292d60b848STomohiro Kusumi char *type; 9302d60b848STomohiro Kusumi if (S_ISDIR(node->type)) 9312d60b848STomohiro Kusumi type = "dir"; 9322d60b848STomohiro Kusumi else if (S_ISREG(node->type)) 9332d60b848STomohiro Kusumi type = "reg"; 9342d60b848STomohiro Kusumi else if (S_ISLNK(node->type)) 9352d60b848STomohiro Kusumi type = "lnk"; 9364d8112c5STomohiro Kusumi else if (S_ISFIFO(node->type)) 9374d8112c5STomohiro Kusumi type = "fifo"; 9382d60b848STomohiro Kusumi else 9392d60b848STomohiro Kusumi type = "???"; 9402d60b848STomohiro Kusumi printf("%*.*s", indent, indent, ""); 9412d60b848STomohiro Kusumi printf("dvp=%p/%d vp=%p/%d \"%s\" %s %s\n", 9422d60b848STomohiro Kusumi dvp, dvp ? VTOI(dvp)->refs : 0, 9432d60b848STomohiro Kusumi vp, vp ? VTOI(vp)->refs : 0, 9442d60b848STomohiro Kusumi node->name, type, msg); 9452d60b848STomohiro Kusumi } else { 9462d60b848STomohiro Kusumi char type; 9472d60b848STomohiro Kusumi if (S_ISDIR(node->type)) 9482d60b848STomohiro Kusumi type = 'd'; 9492d60b848STomohiro Kusumi else if (S_ISREG(node->type)) 9502d60b848STomohiro Kusumi type = 'r'; 9512d60b848STomohiro Kusumi else if (S_ISLNK(node->type)) 9522d60b848STomohiro Kusumi type = 'l'; 9534d8112c5STomohiro Kusumi else if (S_ISFIFO(node->type)) 9544d8112c5STomohiro Kusumi type = 'f'; 9552d60b848STomohiro Kusumi else 9562d60b848STomohiro Kusumi type = '?'; 9572d60b848STomohiro Kusumi printf("%c", type); 9582d60b848STomohiro Kusumi fflush(stdout); 9592d60b848STomohiro Kusumi } 9602d60b848STomohiro Kusumi } 9612d60b848STomohiro Kusumi } 9622d60b848STomohiro Kusumi 9632d60b848STomohiro Kusumi static int 9646bcbb706STomohiro Kusumi hammer2_populate_dir(struct m_vnode *dvp, const char *dir, fsnode *root, 9652d60b848STomohiro Kusumi fsnode *parent, fsinfo_t *fsopts, int depth) 9662d60b848STomohiro Kusumi { 9672d60b848STomohiro Kusumi fsnode *cur; 9686bcbb706STomohiro Kusumi struct m_vnode *vp; 9692d60b848STomohiro Kusumi struct stat st; 9702d60b848STomohiro Kusumi char f[MAXPATHLEN]; 9712d60b848STomohiro Kusumi const char *path; 972213ebac1STomohiro Kusumi int hardlink; 9732d60b848STomohiro Kusumi int error; 9742d60b848STomohiro Kusumi 9752d60b848STomohiro Kusumi assert(dvp != NULL); 9762d60b848STomohiro Kusumi assert(dir != NULL); 9772d60b848STomohiro Kusumi assert(root != NULL); 9782d60b848STomohiro Kusumi assert(parent != NULL); 9792d60b848STomohiro Kusumi assert(fsopts != NULL); 9802d60b848STomohiro Kusumi 9812d60b848STomohiro Kusumi /* assert root directory */ 9822d60b848STomohiro Kusumi assert(S_ISDIR(root->type)); 9832d60b848STomohiro Kusumi assert(!strcmp(root->name, ".")); 9842d60b848STomohiro Kusumi assert(!root->child); 9852d60b848STomohiro Kusumi assert(!root->parent || root->parent->child == root); 9862d60b848STomohiro Kusumi 9872d60b848STomohiro Kusumi hammer2_print(dvp, NULL, root, depth, "enter"); 9882d60b848STomohiro Kusumi if (stat(dir, &st) == -1) 9892d60b848STomohiro Kusumi err(1, "no such path %s", dir); 9902d60b848STomohiro Kusumi if (!S_ISDIR(st.st_mode)) 9912d60b848STomohiro Kusumi errx(1, "no such dir %s", dir); 9922d60b848STomohiro Kusumi 9932d60b848STomohiro Kusumi for (cur = root->next; cur != NULL; cur = cur->next) { 994ddd1d3d1STomohiro Kusumi /* global variable for HAMMER2 vnops */ 995ddd1d3d1STomohiro Kusumi hammer2_curnode = cur; 996ddd1d3d1STomohiro Kusumi 9972d60b848STomohiro Kusumi /* construct source path */ 9982d60b848STomohiro Kusumi if (cur->contents) { 9992d60b848STomohiro Kusumi path = cur->contents; 10002d60b848STomohiro Kusumi } else { 10012d60b848STomohiro Kusumi if (S_ISDIR(cur->type)) { 10022d60b848STomohiro Kusumi /* this should be same as root/path/name */ 10032d60b848STomohiro Kusumi if (snprintf(f, sizeof(f), "%s/%s", 10042d60b848STomohiro Kusumi dir, cur->name) >= (int)sizeof(f)) 1005d5e693f1STomohiro Kusumi errx(1, "path %s too long", f); 10062d60b848STomohiro Kusumi } else { 10072d60b848STomohiro Kusumi if (snprintf(f, sizeof(f), "%s/%s/%s", 10082d60b848STomohiro Kusumi cur->root, cur->path, cur->name) >= (int)sizeof(f)) 1009d5e693f1STomohiro Kusumi errx(1, "path %s too long", f); 10102d60b848STomohiro Kusumi } 10112d60b848STomohiro Kusumi path = f; 10122d60b848STomohiro Kusumi } 1013*2de31a7dSTomohiro Kusumi if (S_ISLNK(cur->type)) { 1014*2de31a7dSTomohiro Kusumi if (lstat(path, &st) == -1) 1015*2de31a7dSTomohiro Kusumi err(1, "no such symlink %s", path); 1016*2de31a7dSTomohiro Kusumi } else { 10172d60b848STomohiro Kusumi if (stat(path, &st) == -1) 1018*2de31a7dSTomohiro Kusumi err(1, "no such path %s", path); 1019*2de31a7dSTomohiro Kusumi } 10202d60b848STomohiro Kusumi 10212d60b848STomohiro Kusumi /* update node state */ 10222d60b848STomohiro Kusumi if ((cur->inode->flags & FI_ALLOCATED) == 0) { 10232d60b848STomohiro Kusumi cur->inode->flags |= FI_ALLOCATED; 10242d60b848STomohiro Kusumi if (cur != root) 10252d60b848STomohiro Kusumi cur->parent = parent; 10262d60b848STomohiro Kusumi } 10272d60b848STomohiro Kusumi 1028213ebac1STomohiro Kusumi /* detect hardlink */ 1029213ebac1STomohiro Kusumi if (cur->inode->flags & FI_WRITTEN) { 1030213ebac1STomohiro Kusumi assert(!S_ISDIR(cur->type)); 1031213ebac1STomohiro Kusumi hardlink = 1; 1032213ebac1STomohiro Kusumi } else { 1033213ebac1STomohiro Kusumi hardlink = 0; 1034213ebac1STomohiro Kusumi } 10352d60b848STomohiro Kusumi cur->inode->flags |= FI_WRITTEN; 10362d60b848STomohiro Kusumi 10372d60b848STomohiro Kusumi /* make sure it doesn't exist yet */ 10382d60b848STomohiro Kusumi vp = NULL; 10392d60b848STomohiro Kusumi error = hammer2_nresolve(dvp, &vp, cur->name, 10402d60b848STomohiro Kusumi strlen(cur->name)); 10412d60b848STomohiro Kusumi if (!error) 10422d60b848STomohiro Kusumi errx(1, "hammer2_nresolve(\"%s\") already exists", 10432d60b848STomohiro Kusumi cur->name); 10442d60b848STomohiro Kusumi hammer2_print(dvp, vp, cur, depth, "nresolve"); 10452d60b848STomohiro Kusumi 10462d60b848STomohiro Kusumi /* if directory, mkdir and recurse */ 10472d60b848STomohiro Kusumi if (S_ISDIR(cur->type)) { 10482d60b848STomohiro Kusumi assert(cur->child); 10492d60b848STomohiro Kusumi 10502d60b848STomohiro Kusumi vp = NULL; 10512d60b848STomohiro Kusumi error = hammer2_nmkdir(dvp, &vp, cur->name, 10528f9d1da1STomohiro Kusumi strlen(cur->name), cur->inode->st.st_mode); 10532d60b848STomohiro Kusumi if (error) 10542d60b848STomohiro Kusumi errx(1, "hammer2_nmkdir(\"%s\") failed: %s", 10552d60b848STomohiro Kusumi cur->name, strerror(error)); 10562d60b848STomohiro Kusumi assert(vp); 10572d60b848STomohiro Kusumi hammer2_print(dvp, vp, cur, depth, "nmkdir"); 10582d60b848STomohiro Kusumi 10592d60b848STomohiro Kusumi error = hammer2_populate_dir(vp, path, cur->child, cur, 10602d60b848STomohiro Kusumi fsopts, depth + 1); 10612d60b848STomohiro Kusumi if (error) 10622d60b848STomohiro Kusumi errx(1, "failed to populate %s: %s", 10632d60b848STomohiro Kusumi path, strerror(error)); 10643bffb051STomohiro Kusumi cur->inode->param = vp; 10652d60b848STomohiro Kusumi continue; 10662d60b848STomohiro Kusumi } 10672d60b848STomohiro Kusumi 10682d60b848STomohiro Kusumi /* if regular file, creat and write its data */ 1069213ebac1STomohiro Kusumi if (S_ISREG(cur->type) && !hardlink) { 10702d60b848STomohiro Kusumi assert(cur->child == NULL); 10712d60b848STomohiro Kusumi 10722d60b848STomohiro Kusumi vp = NULL; 10732d60b848STomohiro Kusumi error = hammer2_ncreate(dvp, &vp, cur->name, 10748f9d1da1STomohiro Kusumi strlen(cur->name), cur->inode->st.st_mode); 10752d60b848STomohiro Kusumi if (error) 10762d60b848STomohiro Kusumi errx(1, "hammer2_ncreate(\"%s\") failed: %s", 10772d60b848STomohiro Kusumi cur->name, strerror(error)); 10782d60b848STomohiro Kusumi assert(vp); 10792d60b848STomohiro Kusumi hammer2_print(dvp, vp, cur, depth, "ncreate"); 10802d60b848STomohiro Kusumi 10812d60b848STomohiro Kusumi error = hammer2_write_file(vp, path, cur); 10822d60b848STomohiro Kusumi if (error) 10832d60b848STomohiro Kusumi errx(1, "hammer2_write_file(\"%s\") failed: %s", 10842d60b848STomohiro Kusumi path, strerror(error)); 10853bffb051STomohiro Kusumi cur->inode->param = vp; 1086213ebac1STomohiro Kusumi continue; 1087213ebac1STomohiro Kusumi } 1088213ebac1STomohiro Kusumi 10892d60b848STomohiro Kusumi /* if symlink, create a symlink against target */ 10902d60b848STomohiro Kusumi if (S_ISLNK(cur->type)) { 10912d60b848STomohiro Kusumi assert(cur->child == NULL); 10922d60b848STomohiro Kusumi 10932d60b848STomohiro Kusumi vp = NULL; 10942d60b848STomohiro Kusumi error = hammer2_nsymlink(dvp, &vp, cur->name, 10958f9d1da1STomohiro Kusumi strlen(cur->name), cur->symlink, 10968f9d1da1STomohiro Kusumi cur->inode->st.st_mode); 10972d60b848STomohiro Kusumi if (error) 10982d60b848STomohiro Kusumi errx(1, "hammer2_nsymlink(\"%s\") failed: %s", 10992d60b848STomohiro Kusumi cur->name, strerror(error)); 11002d60b848STomohiro Kusumi assert(vp); 11012d60b848STomohiro Kusumi hammer2_print(dvp, vp, cur, depth, "nsymlink"); 11023bffb051STomohiro Kusumi cur->inode->param = vp; 11032d60b848STomohiro Kusumi continue; 11042d60b848STomohiro Kusumi } 11052d60b848STomohiro Kusumi 11064d8112c5STomohiro Kusumi /* if fifo, create a fifo */ 110748a07aadSTomohiro Kusumi if (S_ISFIFO(cur->type) && !hardlink) { 11084d8112c5STomohiro Kusumi assert(cur->child == NULL); 11094d8112c5STomohiro Kusumi 11104d8112c5STomohiro Kusumi vp = NULL; 11114d8112c5STomohiro Kusumi error = hammer2_nmknod(dvp, &vp, cur->name, 11128f9d1da1STomohiro Kusumi strlen(cur->name), VFIFO, cur->inode->st.st_mode); 11134d8112c5STomohiro Kusumi if (error) 11144d8112c5STomohiro Kusumi errx(1, "hammer2_nmknod(\"%s\") failed: %s", 11154d8112c5STomohiro Kusumi cur->name, strerror(error)); 11164d8112c5STomohiro Kusumi assert(vp); 11174d8112c5STomohiro Kusumi hammer2_print(dvp, vp, cur, depth, "nmknod"); 11183bffb051STomohiro Kusumi cur->inode->param = vp; 11194d8112c5STomohiro Kusumi continue; 11204d8112c5STomohiro Kusumi } 11214d8112c5STomohiro Kusumi 112248a07aadSTomohiro Kusumi /* if hardlink, creat a hardlink */ 112348a07aadSTomohiro Kusumi if ((S_ISREG(cur->type) || S_ISFIFO(cur->type)) && hardlink) { 112448a07aadSTomohiro Kusumi char buf[64]; 112548a07aadSTomohiro Kusumi assert(cur->child == NULL); 112648a07aadSTomohiro Kusumi 112748a07aadSTomohiro Kusumi /* source vnode must not be NULL */ 11283bffb051STomohiro Kusumi vp = cur->inode->param; 112948a07aadSTomohiro Kusumi assert(vp); 113048a07aadSTomohiro Kusumi /* currently these conditions must be true */ 113148a07aadSTomohiro Kusumi assert(vp->v_data); 113248a07aadSTomohiro Kusumi assert(vp->v_type == VREG || vp->v_type == VFIFO); 113348a07aadSTomohiro Kusumi assert(vp->v_logical); 113448a07aadSTomohiro Kusumi assert(!vp->v_vflushed); 113548a07aadSTomohiro Kusumi assert(vp->v_malloced); 113648a07aadSTomohiro Kusumi assert(VTOI(vp)->refs > 0); 113748a07aadSTomohiro Kusumi 113848a07aadSTomohiro Kusumi error = hammer2_nlink(dvp, vp, cur->name, 113948a07aadSTomohiro Kusumi strlen(cur->name)); 114048a07aadSTomohiro Kusumi if (error) 114148a07aadSTomohiro Kusumi errx(1, "hammer2_nlink(\"%s\") failed: %s", 114248a07aadSTomohiro Kusumi cur->name, strerror(error)); 1143f8a1147cSTomohiro Kusumi snprintf(buf, sizeof(buf), "nlink=%lld", 1144f8a1147cSTomohiro Kusumi (long long)VTOI(vp)->meta.nlinks); 114548a07aadSTomohiro Kusumi hammer2_print(dvp, vp, cur, depth, buf); 114648a07aadSTomohiro Kusumi continue; 114748a07aadSTomohiro Kusumi } 114848a07aadSTomohiro Kusumi 11492d60b848STomohiro Kusumi /* other types are unsupported */ 11502d60b848STomohiro Kusumi printf("ignore %s 0%o\n", path, cur->type); 11512d60b848STomohiro Kusumi } 11522d60b848STomohiro Kusumi 11532d60b848STomohiro Kusumi return 0; 11542d60b848STomohiro Kusumi } 11552d60b848STomohiro Kusumi 11562d60b848STomohiro Kusumi static int 11576bcbb706STomohiro Kusumi hammer2_write_file(struct m_vnode *vp, const char *path, fsnode *node) 11582d60b848STomohiro Kusumi { 11592d60b848STomohiro Kusumi struct stat *st = &node->inode->st; 11602d60b848STomohiro Kusumi size_t nsize, bufsize; 11612d60b848STomohiro Kusumi off_t offset; 11622d60b848STomohiro Kusumi int fd, error; 11632d60b848STomohiro Kusumi char *p; 11642d60b848STomohiro Kusumi 11652d60b848STomohiro Kusumi nsize = st->st_size; 11662d60b848STomohiro Kusumi if (nsize == 0) 11672d60b848STomohiro Kusumi return 0; 11682d60b848STomohiro Kusumi /* check nsize vs maximum file size */ 11692d60b848STomohiro Kusumi 11702d60b848STomohiro Kusumi fd = open(path, O_RDONLY); 11712d60b848STomohiro Kusumi if (fd < 0) 11722d60b848STomohiro Kusumi err(1, "failed to open %s", path); 11732d60b848STomohiro Kusumi 11742d60b848STomohiro Kusumi p = mmap(0, nsize, PROT_READ, MAP_FILE|MAP_PRIVATE, fd, 0); 11752d60b848STomohiro Kusumi if (p == MAP_FAILED) 11762d60b848STomohiro Kusumi err(1, "failed to mmap %s", path); 11772d60b848STomohiro Kusumi close(fd); 11782d60b848STomohiro Kusumi 11792d60b848STomohiro Kusumi for (offset = 0; offset < nsize; ) { 11802d60b848STomohiro Kusumi bufsize = MIN(nsize - offset, HAMMER2_PBUFSIZE); 11812d60b848STomohiro Kusumi assert(bufsize <= HAMMER2_PBUFSIZE); 11822d60b848STomohiro Kusumi error = hammer2_write(vp, p + offset, bufsize, offset); 11832d60b848STomohiro Kusumi if (error) 11842d60b848STomohiro Kusumi errx(1, "failed to write to %s vnode: %s", 11852d60b848STomohiro Kusumi path, strerror(error)); 11862d60b848STomohiro Kusumi offset += bufsize; 11872d60b848STomohiro Kusumi if (bufsize == HAMMER2_PBUFSIZE) 11882d60b848STomohiro Kusumi assert((offset & (HAMMER2_PBUFSIZE - 1)) == 0); 11892d60b848STomohiro Kusumi } 11902d60b848STomohiro Kusumi munmap(p, nsize); 11912d60b848STomohiro Kusumi 11922d60b848STomohiro Kusumi return 0; 11932d60b848STomohiro Kusumi } 1194a63188c8STomohiro Kusumi 1195f72350acSTomohiro Kusumi static int 11966857f034STomohiro Kusumi trim_char(char *p, char c) 11976857f034STomohiro Kusumi { 11986857f034STomohiro Kusumi char *o, tmp[PATH_MAX]; 1199bca6a9a0STomohiro Kusumi bool prev_was_c; 12006857f034STomohiro Kusumi size_t n; 12016857f034STomohiro Kusumi int i; 12026857f034STomohiro Kusumi 12036857f034STomohiro Kusumi strlcpy(tmp, p, sizeof(tmp)); 12046857f034STomohiro Kusumi if (strncmp(tmp, p, sizeof(tmp))) 12056857f034STomohiro Kusumi return ENOSPC; 12066857f034STomohiro Kusumi 12076857f034STomohiro Kusumi /* trim consecutive */ 1208bca6a9a0STomohiro Kusumi prev_was_c = false; 12096857f034STomohiro Kusumi o = p; 12106857f034STomohiro Kusumi n = strlen(p); 12116857f034STomohiro Kusumi 12126857f034STomohiro Kusumi for (i = 0; i < n; i++) { 12136857f034STomohiro Kusumi if (tmp[i] == c) { 1214bca6a9a0STomohiro Kusumi if (!prev_was_c) 12156857f034STomohiro Kusumi *p++ = tmp[i]; 1216bca6a9a0STomohiro Kusumi prev_was_c = true; 12176857f034STomohiro Kusumi } else { 12186857f034STomohiro Kusumi *p++ = tmp[i]; 1219bca6a9a0STomohiro Kusumi prev_was_c = false; 12206857f034STomohiro Kusumi } 12216857f034STomohiro Kusumi } 12226857f034STomohiro Kusumi *p = 0; 12236857f034STomohiro Kusumi assert(strlen(p) <= strlen(tmp)); 12246857f034STomohiro Kusumi 12256857f034STomohiro Kusumi /* assert no consecutive */ 1226bca6a9a0STomohiro Kusumi prev_was_c = false; 12276857f034STomohiro Kusumi p = o; 12286857f034STomohiro Kusumi n = strlen(p); 12296857f034STomohiro Kusumi 12306857f034STomohiro Kusumi for (i = 0; i < n; i++) { 12316857f034STomohiro Kusumi if (p[i] == c) { 1232bca6a9a0STomohiro Kusumi assert(!prev_was_c); 1233bca6a9a0STomohiro Kusumi prev_was_c = true; 12346857f034STomohiro Kusumi } else { 1235bca6a9a0STomohiro Kusumi prev_was_c = false; 12366857f034STomohiro Kusumi } 12376857f034STomohiro Kusumi } 12386857f034STomohiro Kusumi 12396857f034STomohiro Kusumi /* trim leading */ 12406857f034STomohiro Kusumi if (*p == c) 12416857f034STomohiro Kusumi memmove(p, p + 1, strlen(p + 1) + 1); 12426857f034STomohiro Kusumi assert(*p != '/'); 12436857f034STomohiro Kusumi 12446857f034STomohiro Kusumi /* trim trailing */ 12456857f034STomohiro Kusumi p += strlen(p); 12466857f034STomohiro Kusumi p--; 12476857f034STomohiro Kusumi if (*p == c) 12486857f034STomohiro Kusumi *p = 0; 12496857f034STomohiro Kusumi assert(p[strlen(p) - 1] != '/'); 12506857f034STomohiro Kusumi 12516857f034STomohiro Kusumi return 0; 12526857f034STomohiro Kusumi } 12536857f034STomohiro Kusumi 12546857f034STomohiro Kusumi static int 12556857f034STomohiro Kusumi trim_slash(char *p) 12566857f034STomohiro Kusumi { 12576857f034STomohiro Kusumi return trim_char(p, '/'); 12586857f034STomohiro Kusumi } 12596857f034STomohiro Kusumi 12606857f034STomohiro Kusumi static int 1261f72350acSTomohiro Kusumi hammer2_version_get(struct m_vnode *vp) 1262f72350acSTomohiro Kusumi { 1263f72350acSTomohiro Kusumi hammer2_dev_t *hmp; 1264f72350acSTomohiro Kusumi 1265f72350acSTomohiro Kusumi hmp = VTOI(vp)->pmp->pfs_hmps[0]; 1266f72350acSTomohiro Kusumi if (hmp == NULL) 1267f72350acSTomohiro Kusumi return EINVAL; 1268f72350acSTomohiro Kusumi 1269f72350acSTomohiro Kusumi printf("version: %d\n", hmp->voldata.version); 1270f72350acSTomohiro Kusumi 1271f72350acSTomohiro Kusumi return 0; 1272f72350acSTomohiro Kusumi } 1273f72350acSTomohiro Kusumi 12743999233bSTomohiro Kusumi struct pfs_entry { 12753999233bSTomohiro Kusumi TAILQ_ENTRY(pfs_entry) entry; 12763999233bSTomohiro Kusumi char name[NAME_MAX+1]; 12773999233bSTomohiro Kusumi char s[NAME_MAX+1]; 12783999233bSTomohiro Kusumi }; 12793999233bSTomohiro Kusumi 12803999233bSTomohiro Kusumi static int 12813999233bSTomohiro Kusumi hammer2_pfs_get(struct m_vnode *vp) 12823999233bSTomohiro Kusumi { 12833999233bSTomohiro Kusumi hammer2_ioc_pfs_t pfs; 12843999233bSTomohiro Kusumi TAILQ_HEAD(, pfs_entry) head; 12853999233bSTomohiro Kusumi struct pfs_entry *p, *e; 12863999233bSTomohiro Kusumi char *pfs_id_str; 12873999233bSTomohiro Kusumi const char *type_str; 12883999233bSTomohiro Kusumi int error; 12893999233bSTomohiro Kusumi 12903999233bSTomohiro Kusumi bzero(&pfs, sizeof(pfs)); 12913999233bSTomohiro Kusumi TAILQ_INIT(&head); 12923999233bSTomohiro Kusumi 12933999233bSTomohiro Kusumi while ((pfs.name_key = pfs.name_next) != (hammer2_key_t)-1) { 12943999233bSTomohiro Kusumi error = hammer2_ioctl_pfs_get(VTOI(vp), &pfs); 12953999233bSTomohiro Kusumi if (error) 12963999233bSTomohiro Kusumi return error; 12973999233bSTomohiro Kusumi 12983999233bSTomohiro Kusumi pfs_id_str = NULL; 12993999233bSTomohiro Kusumi hammer2_uuid_to_str(&pfs.pfs_clid, &pfs_id_str); 13003999233bSTomohiro Kusumi 13013999233bSTomohiro Kusumi if (pfs.pfs_type == HAMMER2_PFSTYPE_MASTER) { 13023999233bSTomohiro Kusumi if (pfs.pfs_subtype == HAMMER2_PFSSUBTYPE_NONE) 13033999233bSTomohiro Kusumi type_str = "MASTER"; 13043999233bSTomohiro Kusumi else 13053999233bSTomohiro Kusumi type_str = hammer2_pfssubtype_to_str( 13063999233bSTomohiro Kusumi pfs.pfs_subtype); 13073999233bSTomohiro Kusumi } else { 13083999233bSTomohiro Kusumi type_str = hammer2_pfstype_to_str(pfs.pfs_type); 13093999233bSTomohiro Kusumi } 131006d1ac82STomohiro Kusumi e = ecalloc(1, sizeof(*e)); 13113999233bSTomohiro Kusumi snprintf(e->name, sizeof(e->name), "%s", pfs.name); 13123999233bSTomohiro Kusumi snprintf(e->s, sizeof(e->s), "%-11s %s", type_str, pfs_id_str); 13133999233bSTomohiro Kusumi free(pfs_id_str); 13143999233bSTomohiro Kusumi 13153999233bSTomohiro Kusumi p = TAILQ_FIRST(&head); 13163999233bSTomohiro Kusumi while (p) { 13173999233bSTomohiro Kusumi if (strcmp(e->name, p->name) <= 0) { 13183999233bSTomohiro Kusumi TAILQ_INSERT_BEFORE(p, e, entry); 13193999233bSTomohiro Kusumi break; 13203999233bSTomohiro Kusumi } 13213999233bSTomohiro Kusumi p = TAILQ_NEXT(p, entry); 13223999233bSTomohiro Kusumi } 13233999233bSTomohiro Kusumi if (!p) 13243999233bSTomohiro Kusumi TAILQ_INSERT_TAIL(&head, e, entry); 13253999233bSTomohiro Kusumi } 13263999233bSTomohiro Kusumi 13273999233bSTomohiro Kusumi printf("Type " 13283999233bSTomohiro Kusumi "ClusterId (pfs_clid) " 13293999233bSTomohiro Kusumi "Label\n"); 13303999233bSTomohiro Kusumi while ((p = TAILQ_FIRST(&head)) != NULL) { 13313999233bSTomohiro Kusumi printf("%s %s\n", p->s, p->name); 13323999233bSTomohiro Kusumi TAILQ_REMOVE(&head, p, entry); 13333999233bSTomohiro Kusumi free(p); 13343999233bSTomohiro Kusumi } 13353999233bSTomohiro Kusumi 13363999233bSTomohiro Kusumi return 0; 13373999233bSTomohiro Kusumi } 13383999233bSTomohiro Kusumi 13393999233bSTomohiro Kusumi static int 13403999233bSTomohiro Kusumi hammer2_pfs_lookup(struct m_vnode *vp, const char *pfs_name) 13413999233bSTomohiro Kusumi { 13423999233bSTomohiro Kusumi hammer2_ioc_pfs_t pfs; 13433999233bSTomohiro Kusumi char *pfs_id_str; 13443999233bSTomohiro Kusumi int error; 13453999233bSTomohiro Kusumi 13463999233bSTomohiro Kusumi bzero(&pfs, sizeof(pfs)); 13473999233bSTomohiro Kusumi strlcpy(pfs.name, pfs_name, sizeof(pfs.name)); 13483999233bSTomohiro Kusumi 13493999233bSTomohiro Kusumi error = hammer2_ioctl_pfs_lookup(VTOI(vp), &pfs); 13503999233bSTomohiro Kusumi if (error == 0) { 13513999233bSTomohiro Kusumi printf("name: %s\n", pfs.name); 13523999233bSTomohiro Kusumi printf("type: %s\n", hammer2_pfstype_to_str(pfs.pfs_type)); 13533999233bSTomohiro Kusumi printf("subtype: %s\n", 13543999233bSTomohiro Kusumi hammer2_pfssubtype_to_str(pfs.pfs_subtype)); 13553999233bSTomohiro Kusumi 13563999233bSTomohiro Kusumi pfs_id_str = NULL; 13573999233bSTomohiro Kusumi hammer2_uuid_to_str(&pfs.pfs_fsid, &pfs_id_str); 13583999233bSTomohiro Kusumi printf("fsid: %s\n", pfs_id_str); 13593999233bSTomohiro Kusumi free(pfs_id_str); 13603999233bSTomohiro Kusumi 13613999233bSTomohiro Kusumi pfs_id_str = NULL; 13623999233bSTomohiro Kusumi hammer2_uuid_to_str(&pfs.pfs_clid, &pfs_id_str); 13633999233bSTomohiro Kusumi printf("clid: %s\n", pfs_id_str); 13643999233bSTomohiro Kusumi free(pfs_id_str); 13653999233bSTomohiro Kusumi } 13663999233bSTomohiro Kusumi 13673999233bSTomohiro Kusumi return error; 13683999233bSTomohiro Kusumi } 13693999233bSTomohiro Kusumi 13703999233bSTomohiro Kusumi static int 13713999233bSTomohiro Kusumi hammer2_pfs_create(struct m_vnode *vp, const char *pfs_name) 13723999233bSTomohiro Kusumi { 13733999233bSTomohiro Kusumi hammer2_ioc_pfs_t pfs; 13743999233bSTomohiro Kusumi int error; 13753999233bSTomohiro Kusumi 13763999233bSTomohiro Kusumi bzero(&pfs, sizeof(pfs)); 13773999233bSTomohiro Kusumi strlcpy(pfs.name, pfs_name, sizeof(pfs.name)); 13783999233bSTomohiro Kusumi pfs.pfs_type = HAMMER2_PFSTYPE_MASTER; 13793999233bSTomohiro Kusumi uuid_create(&pfs.pfs_clid, NULL); 13803999233bSTomohiro Kusumi uuid_create(&pfs.pfs_fsid, NULL); 13813999233bSTomohiro Kusumi 13823999233bSTomohiro Kusumi error = hammer2_ioctl_pfs_create(VTOI(vp), &pfs); 13833999233bSTomohiro Kusumi if (error == EEXIST) 13843999233bSTomohiro Kusumi fprintf(stderr, 13853999233bSTomohiro Kusumi "NOTE: Typically the same name is " 13863999233bSTomohiro Kusumi "used for cluster elements on " 13873999233bSTomohiro Kusumi "different mounts,\n" 13883999233bSTomohiro Kusumi " but cluster elements on the " 13893999233bSTomohiro Kusumi "same mount require unique names.\n" 13903999233bSTomohiro Kusumi "hammer2: pfs_create(%s): already present\n", 13913999233bSTomohiro Kusumi pfs_name); 13923999233bSTomohiro Kusumi 13933999233bSTomohiro Kusumi return error; 13943999233bSTomohiro Kusumi } 13953999233bSTomohiro Kusumi 13963999233bSTomohiro Kusumi static int 13973999233bSTomohiro Kusumi hammer2_pfs_delete(struct m_vnode *vp, const char *pfs_name) 13983999233bSTomohiro Kusumi { 13993999233bSTomohiro Kusumi hammer2_ioc_pfs_t pfs; 14003999233bSTomohiro Kusumi 14013999233bSTomohiro Kusumi bzero(&pfs, sizeof(pfs)); 14023999233bSTomohiro Kusumi strlcpy(pfs.name, pfs_name, sizeof(pfs.name)); 14033999233bSTomohiro Kusumi 14043999233bSTomohiro Kusumi return hammer2_ioctl_pfs_delete(VTOI(vp), &pfs); 14053999233bSTomohiro Kusumi } 14063999233bSTomohiro Kusumi 14073999233bSTomohiro Kusumi static int 14083999233bSTomohiro Kusumi hammer2_pfs_snapshot(struct m_vnode *vp, const char *pfs_name, 14093999233bSTomohiro Kusumi const char *mount_label) 14103999233bSTomohiro Kusumi { 14113999233bSTomohiro Kusumi hammer2_ioc_pfs_t pfs; 14123999233bSTomohiro Kusumi struct tm *tp; 14133999233bSTomohiro Kusumi time_t t; 14143999233bSTomohiro Kusumi 14153999233bSTomohiro Kusumi bzero(&pfs, sizeof(pfs)); 14163999233bSTomohiro Kusumi strlcpy(pfs.name, pfs_name, sizeof(pfs.name)); 14173999233bSTomohiro Kusumi 14183999233bSTomohiro Kusumi if (strlen(pfs.name) == 0) { 14193999233bSTomohiro Kusumi time(&t); 14203999233bSTomohiro Kusumi tp = localtime(&t); 14213999233bSTomohiro Kusumi snprintf(pfs.name, sizeof(pfs.name), 14223999233bSTomohiro Kusumi "%s.%04d%02d%02d.%02d%02d%02d", 14233999233bSTomohiro Kusumi mount_label, 14243999233bSTomohiro Kusumi tp->tm_year + 1900, 14253999233bSTomohiro Kusumi tp->tm_mon + 1, 14263999233bSTomohiro Kusumi tp->tm_mday, 14273999233bSTomohiro Kusumi tp->tm_hour, 14283999233bSTomohiro Kusumi tp->tm_min, 14293999233bSTomohiro Kusumi tp->tm_sec); 14303999233bSTomohiro Kusumi } 14313999233bSTomohiro Kusumi 14323999233bSTomohiro Kusumi return hammer2_ioctl_pfs_snapshot(VTOI(vp), &pfs); 14333999233bSTomohiro Kusumi } 14343999233bSTomohiro Kusumi 14353999233bSTomohiro Kusumi static int 1436f804c425STomohiro Kusumi hammer2_inode_getx(struct m_vnode *dvp, const char *f) 1437f804c425STomohiro Kusumi { 1438f804c425STomohiro Kusumi hammer2_ioc_inode_t inode; 1439f804c425STomohiro Kusumi hammer2_inode_t *ip; 1440f804c425STomohiro Kusumi hammer2_inode_meta_t *meta; 1441f804c425STomohiro Kusumi struct m_vnode *vp; 1442f804c425STomohiro Kusumi char *o, *p, *name, *str = NULL; 1443f804c425STomohiro Kusumi int error; 1444f804c425STomohiro Kusumi uuid_t uuid; 1445f804c425STomohiro Kusumi 1446f804c425STomohiro Kusumi assert(strlen(f) > 0); 14476857f034STomohiro Kusumi o = p = name = strdup(f); 1448f804c425STomohiro Kusumi 14496857f034STomohiro Kusumi error = trim_slash(p); 14506857f034STomohiro Kusumi if (error) 14516857f034STomohiro Kusumi return error; 1452f804c425STomohiro Kusumi if (strlen(p) == 0) 1453f804c425STomohiro Kusumi return EINVAL; 1454f804c425STomohiro Kusumi 1455f804c425STomohiro Kusumi while ((p = strchr(p, '/')) != NULL) { 1456f804c425STomohiro Kusumi *p++ = 0; /* NULL terminate name */ 1457f804c425STomohiro Kusumi vp = NULL; 1458f804c425STomohiro Kusumi error = hammer2_nresolve(dvp, &vp, name, strlen(name)); 1459f804c425STomohiro Kusumi if (error) 1460f804c425STomohiro Kusumi return error; 1461f804c425STomohiro Kusumi 1462f804c425STomohiro Kusumi ip = VTOI(vp); 1463f804c425STomohiro Kusumi assert(ip->meta.type == HAMMER2_OBJTYPE_DIRECTORY); 1464f804c425STomohiro Kusumi 1465f804c425STomohiro Kusumi dvp = vp; 1466f804c425STomohiro Kusumi name = p; 1467f804c425STomohiro Kusumi } 1468f804c425STomohiro Kusumi 1469f804c425STomohiro Kusumi error = hammer2_nresolve(dvp, &vp, name, strlen(name)); 1470f804c425STomohiro Kusumi if (error) 1471f804c425STomohiro Kusumi return error; 1472f804c425STomohiro Kusumi 1473f804c425STomohiro Kusumi bzero(&inode, sizeof(inode)); 1474f804c425STomohiro Kusumi error = hammer2_ioctl_inode_get(VTOI(vp), &inode); 1475f804c425STomohiro Kusumi if (error) 1476f804c425STomohiro Kusumi return error; 1477f804c425STomohiro Kusumi 1478f804c425STomohiro Kusumi meta = &inode.ip_data.meta; 1479f804c425STomohiro Kusumi printf("--------------------\n"); 1480f804c425STomohiro Kusumi printf("flags = 0x%x\n", inode.flags); 1481f804c425STomohiro Kusumi printf("data_count = %ju\n", (uintmax_t)inode.data_count); 1482f804c425STomohiro Kusumi printf("inode_count = %ju\n", (uintmax_t)inode.inode_count); 1483f804c425STomohiro Kusumi printf("--------------------\n"); 1484f804c425STomohiro Kusumi printf("version = %u\n", meta->version); 1485f804c425STomohiro Kusumi printf("pfs_subtype = %u (%s)\n", meta->pfs_subtype, 1486f804c425STomohiro Kusumi hammer2_pfssubtype_to_str(meta->pfs_subtype)); 1487f804c425STomohiro Kusumi printf("uflags = 0x%x\n", (unsigned int)meta->uflags); 1488f804c425STomohiro Kusumi printf("rmajor = %u\n", meta->rmajor); 1489f804c425STomohiro Kusumi printf("rminor = %u\n", meta->rminor); 1490f804c425STomohiro Kusumi printf("ctime = %s\n", hammer2_time64_to_str(meta->ctime, &str)); 1491f804c425STomohiro Kusumi printf("mtime = %s\n", hammer2_time64_to_str(meta->mtime, &str)); 1492f804c425STomohiro Kusumi printf("atime = %s\n", hammer2_time64_to_str(meta->atime, &str)); 1493f804c425STomohiro Kusumi printf("btime = %s\n", hammer2_time64_to_str(meta->btime, &str)); 1494f804c425STomohiro Kusumi uuid = meta->uid; 1495f804c425STomohiro Kusumi printf("uid = %s\n", hammer2_uuid_to_str(&uuid, &str)); 1496f804c425STomohiro Kusumi uuid = meta->gid; 1497f804c425STomohiro Kusumi printf("gid = %s\n", hammer2_uuid_to_str(&uuid, &str)); 1498f804c425STomohiro Kusumi printf("type = %u (%s)\n", meta->type, 1499f804c425STomohiro Kusumi hammer2_iptype_to_str(meta->type)); 1500f804c425STomohiro Kusumi printf("op_flags = 0x%x\n", meta->op_flags); 1501f804c425STomohiro Kusumi printf("cap_flags = 0x%x\n", meta->cap_flags); 1502f804c425STomohiro Kusumi printf("mode = 0%o\n", meta->mode); 1503f804c425STomohiro Kusumi printf("inum = 0x%jx\n", (uintmax_t)meta->inum); 1504f804c425STomohiro Kusumi printf("size = %ju\n", (uintmax_t)meta->size); 1505f804c425STomohiro Kusumi printf("nlinks = %ju\n", (uintmax_t)meta->nlinks); 1506f804c425STomohiro Kusumi printf("iparent = 0x%jx\n", (uintmax_t)meta->iparent); 1507f804c425STomohiro Kusumi printf("name_key = 0x%jx\n", (uintmax_t)meta->name_key); 1508f804c425STomohiro Kusumi printf("name_len = %u\n", meta->name_len); 1509f804c425STomohiro Kusumi printf("ncopies = %u\n", meta->ncopies); 1510f804c425STomohiro Kusumi printf("comp_algo = %u\n", meta->comp_algo); 1511f804c425STomohiro Kusumi printf("target_type = %u\n", meta->target_type); 1512f804c425STomohiro Kusumi printf("check_algo = %u\n", meta->check_algo); 1513f804c425STomohiro Kusumi printf("pfs_nmasters = %u\n", meta->pfs_nmasters); 1514f804c425STomohiro Kusumi printf("pfs_type = %u (%s)\n", meta->pfs_type, 1515f804c425STomohiro Kusumi hammer2_pfstype_to_str(meta->pfs_type)); 1516f804c425STomohiro Kusumi printf("pfs_inum = 0x%jx\n", (uintmax_t)meta->pfs_inum); 1517f804c425STomohiro Kusumi uuid = meta->pfs_clid; 1518f804c425STomohiro Kusumi printf("pfs_clid = %s\n", hammer2_uuid_to_str(&uuid, &str)); 1519f804c425STomohiro Kusumi uuid = meta->pfs_fsid; 1520f804c425STomohiro Kusumi printf("pfs_fsid = %s\n", hammer2_uuid_to_str(&uuid, &str)); 1521f804c425STomohiro Kusumi printf("data_quota = 0x%jx\n", (uintmax_t)meta->data_quota); 1522f804c425STomohiro Kusumi printf("inode_quota = 0x%jx\n", (uintmax_t)meta->inode_quota); 1523f804c425STomohiro Kusumi printf("pfs_lsnap_tid = 0x%jx\n", (uintmax_t)meta->pfs_lsnap_tid); 1524f804c425STomohiro Kusumi printf("decrypt_check = 0x%jx\n", (uintmax_t)meta->decrypt_check); 1525f804c425STomohiro Kusumi printf("--------------------\n"); 1526f804c425STomohiro Kusumi 1527f804c425STomohiro Kusumi free(o); 1528f804c425STomohiro Kusumi 1529f804c425STomohiro Kusumi return error; 1530f804c425STomohiro Kusumi } 1531f804c425STomohiro Kusumi 1532f804c425STomohiro Kusumi static int 1533465e1141STomohiro Kusumi hammer2_inode_setcheck(struct m_vnode *dvp, const char *f) 1534465e1141STomohiro Kusumi { 1535465e1141STomohiro Kusumi hammer2_ioc_inode_t inode; 1536465e1141STomohiro Kusumi hammer2_inode_t *ip; 1537465e1141STomohiro Kusumi struct m_vnode *vp; 1538465e1141STomohiro Kusumi char *o, *p, *name, *check_algo_str; 1539465e1141STomohiro Kusumi const char *checks[] = { "none", "disabled", "crc32", "xxhash64", 1540465e1141STomohiro Kusumi "sha192", }; 1541465e1141STomohiro Kusumi int check_algo_idx, error; 1542465e1141STomohiro Kusumi uint8_t check_algo; 1543465e1141STomohiro Kusumi 1544465e1141STomohiro Kusumi assert(strlen(f) > 0); 1545465e1141STomohiro Kusumi o = p = strdup(f); 1546465e1141STomohiro Kusumi 1547465e1141STomohiro Kusumi p = strrchr(p, ':'); 1548465e1141STomohiro Kusumi if (p == NULL) 1549465e1141STomohiro Kusumi return EINVAL; 1550465e1141STomohiro Kusumi 1551465e1141STomohiro Kusumi *p++ = 0; /* NULL terminate path */ 1552465e1141STomohiro Kusumi check_algo_str = p; 1553465e1141STomohiro Kusumi name = p = o; 1554465e1141STomohiro Kusumi 15556857f034STomohiro Kusumi error = trim_slash(p); 15566857f034STomohiro Kusumi if (error) 15576857f034STomohiro Kusumi return error; 1558465e1141STomohiro Kusumi if (strlen(p) == 0 || strlen(check_algo_str) == 0) 1559465e1141STomohiro Kusumi return EINVAL; 1560465e1141STomohiro Kusumi 1561465e1141STomohiro Kusumi /* convert check_algo_str to check_algo_idx */ 15626857f034STomohiro Kusumi check_algo_idx = nitems(checks); 1563465e1141STomohiro Kusumi while (--check_algo_idx >= 0) 1564465e1141STomohiro Kusumi if (strcasecmp(check_algo_str, checks[check_algo_idx]) == 0) 1565465e1141STomohiro Kusumi break; 1566465e1141STomohiro Kusumi if (check_algo_idx < 0) { 1567465e1141STomohiro Kusumi if (strcasecmp(check_algo_str, "default") == 0) { 1568465e1141STomohiro Kusumi check_algo_str = "xxhash64"; 1569465e1141STomohiro Kusumi check_algo_idx = HAMMER2_CHECK_XXHASH64; 1570465e1141STomohiro Kusumi } else if (strcasecmp(check_algo_str, "disabled") == 0) { 1571465e1141STomohiro Kusumi check_algo_str = "disabled"; 1572465e1141STomohiro Kusumi check_algo_idx = HAMMER2_CHECK_DISABLED; 1573465e1141STomohiro Kusumi } else { 1574465e1141STomohiro Kusumi printf("invalid check_algo_str: %s\n", check_algo_str); 1575465e1141STomohiro Kusumi return EINVAL; 1576465e1141STomohiro Kusumi } 1577465e1141STomohiro Kusumi } 1578465e1141STomohiro Kusumi check_algo = HAMMER2_ENC_ALGO(check_algo_idx); 1579465e1141STomohiro Kusumi printf("change %s to algo %d (%s)\n", p, check_algo, check_algo_str); 1580465e1141STomohiro Kusumi 1581465e1141STomohiro Kusumi while ((p = strchr(p, '/')) != NULL) { 1582465e1141STomohiro Kusumi *p++ = 0; /* NULL terminate name */ 1583465e1141STomohiro Kusumi vp = NULL; 1584465e1141STomohiro Kusumi error = hammer2_nresolve(dvp, &vp, name, strlen(name)); 1585465e1141STomohiro Kusumi if (error) 1586465e1141STomohiro Kusumi return error; 1587465e1141STomohiro Kusumi 1588465e1141STomohiro Kusumi ip = VTOI(vp); 1589465e1141STomohiro Kusumi assert(ip->meta.type == HAMMER2_OBJTYPE_DIRECTORY); 1590465e1141STomohiro Kusumi 1591465e1141STomohiro Kusumi dvp = vp; 1592465e1141STomohiro Kusumi name = p; 1593465e1141STomohiro Kusumi } 1594465e1141STomohiro Kusumi 1595465e1141STomohiro Kusumi error = hammer2_nresolve(dvp, &vp, name, strlen(name)); 1596465e1141STomohiro Kusumi if (error) 1597465e1141STomohiro Kusumi return error; 1598465e1141STomohiro Kusumi ip = VTOI(vp); 1599465e1141STomohiro Kusumi 1600465e1141STomohiro Kusumi bzero(&inode, sizeof(inode)); 1601465e1141STomohiro Kusumi error = hammer2_ioctl_inode_get(ip, &inode); 1602465e1141STomohiro Kusumi if (error) 1603465e1141STomohiro Kusumi return error; 1604465e1141STomohiro Kusumi 1605465e1141STomohiro Kusumi inode.flags |= HAMMER2IOC_INODE_FLAG_CHECK; 1606465e1141STomohiro Kusumi inode.ip_data.meta.check_algo = check_algo; 1607465e1141STomohiro Kusumi error = hammer2_ioctl_inode_set(ip, &inode); 1608465e1141STomohiro Kusumi if (error) 1609465e1141STomohiro Kusumi return error; 1610465e1141STomohiro Kusumi 1611465e1141STomohiro Kusumi free(o); 1612465e1141STomohiro Kusumi 1613465e1141STomohiro Kusumi return error; 1614465e1141STomohiro Kusumi } 1615465e1141STomohiro Kusumi 1616465e1141STomohiro Kusumi static int 1617465e1141STomohiro Kusumi hammer2_inode_setcomp(struct m_vnode *dvp, const char *f) 1618465e1141STomohiro Kusumi { 1619465e1141STomohiro Kusumi hammer2_ioc_inode_t inode; 1620465e1141STomohiro Kusumi hammer2_inode_t *ip; 1621465e1141STomohiro Kusumi struct m_vnode *vp; 1622465e1141STomohiro Kusumi char *o, *p, *name, *comp_algo_str, *comp_level_str; 1623465e1141STomohiro Kusumi const char *comps[] = { "none", "autozero", "lz4", "zlib", }; 1624465e1141STomohiro Kusumi int comp_algo_idx, comp_level_idx, error; 1625465e1141STomohiro Kusumi uint8_t comp_algo, comp_level; 1626465e1141STomohiro Kusumi 1627465e1141STomohiro Kusumi assert(strlen(f) > 0); 1628465e1141STomohiro Kusumi o = p = strdup(f); 1629465e1141STomohiro Kusumi 1630465e1141STomohiro Kusumi p = strrchr(p, ':'); 1631465e1141STomohiro Kusumi if (p == NULL) 1632465e1141STomohiro Kusumi return EINVAL; 1633465e1141STomohiro Kusumi 1634465e1141STomohiro Kusumi *p++ = 0; /* NULL terminate comp_algo_str */ 1635465e1141STomohiro Kusumi comp_level_str = p; 1636465e1141STomohiro Kusumi p = o; 1637465e1141STomohiro Kusumi 1638465e1141STomohiro Kusumi p = strrchr(p, ':'); 1639465e1141STomohiro Kusumi if (p == NULL) { 1640465e1141STomohiro Kusumi /* comp_level_str not specified */ 1641465e1141STomohiro Kusumi comp_algo_str = comp_level_str; 1642465e1141STomohiro Kusumi comp_level_str = NULL; 1643465e1141STomohiro Kusumi } else { 1644465e1141STomohiro Kusumi *p++ = 0; /* NULL terminate path */ 1645465e1141STomohiro Kusumi comp_algo_str = p; 1646465e1141STomohiro Kusumi } 1647465e1141STomohiro Kusumi name = p = o; 1648465e1141STomohiro Kusumi 16496857f034STomohiro Kusumi error = trim_slash(p); 16506857f034STomohiro Kusumi if (error) 16516857f034STomohiro Kusumi return error; 1652465e1141STomohiro Kusumi if (strlen(p) == 0 || strlen(comp_algo_str) == 0) 1653465e1141STomohiro Kusumi return EINVAL; 1654465e1141STomohiro Kusumi 1655465e1141STomohiro Kusumi /* convert comp_algo_str to comp_algo_idx */ 16566857f034STomohiro Kusumi comp_algo_idx = nitems(comps); 1657465e1141STomohiro Kusumi while (--comp_algo_idx >= 0) 1658465e1141STomohiro Kusumi if (strcasecmp(comp_algo_str, comps[comp_algo_idx]) == 0) 1659465e1141STomohiro Kusumi break; 1660465e1141STomohiro Kusumi if (comp_algo_idx < 0) { 1661465e1141STomohiro Kusumi if (strcasecmp(comp_algo_str, "default") == 0) { 1662465e1141STomohiro Kusumi comp_algo_str = "lz4"; 1663465e1141STomohiro Kusumi comp_algo_idx = HAMMER2_COMP_LZ4; 1664465e1141STomohiro Kusumi } else if (strcasecmp(comp_algo_str, "disabled") == 0) { 1665465e1141STomohiro Kusumi comp_algo_str = "autozero"; 1666465e1141STomohiro Kusumi comp_algo_idx = HAMMER2_COMP_AUTOZERO; 1667465e1141STomohiro Kusumi } else { 1668465e1141STomohiro Kusumi printf("invalid comp_algo_str: %s\n", comp_algo_str); 1669465e1141STomohiro Kusumi return EINVAL; 1670465e1141STomohiro Kusumi } 1671465e1141STomohiro Kusumi } 1672465e1141STomohiro Kusumi comp_algo = HAMMER2_ENC_ALGO(comp_algo_idx); 1673465e1141STomohiro Kusumi 1674465e1141STomohiro Kusumi /* convert comp_level_str to comp_level_idx */ 1675465e1141STomohiro Kusumi if (comp_level_str == NULL) { 1676465e1141STomohiro Kusumi comp_level_idx = 0; 1677bca6a9a0STomohiro Kusumi } else if (isdigit((int)comp_level_str[0])) { 1678465e1141STomohiro Kusumi comp_level_idx = strtol(comp_level_str, NULL, 0); 1679465e1141STomohiro Kusumi } else if (strcasecmp(comp_level_str, "default") == 0) { 1680465e1141STomohiro Kusumi comp_level_idx = 0; 1681465e1141STomohiro Kusumi } else { 1682465e1141STomohiro Kusumi printf("invalid comp_level_str: %s\n", comp_level_str); 1683465e1141STomohiro Kusumi return EINVAL; 1684465e1141STomohiro Kusumi } 1685465e1141STomohiro Kusumi if (comp_level_idx) { 1686465e1141STomohiro Kusumi switch (comp_algo) { 1687465e1141STomohiro Kusumi case HAMMER2_COMP_ZLIB: 1688465e1141STomohiro Kusumi if (comp_level_idx < 6 || comp_level_idx > 9) { 1689465e1141STomohiro Kusumi printf("unsupported comp_level %d for %s\n", 1690465e1141STomohiro Kusumi comp_level_idx, comp_algo_str); 1691465e1141STomohiro Kusumi return EINVAL; 1692465e1141STomohiro Kusumi } 1693465e1141STomohiro Kusumi break; 1694465e1141STomohiro Kusumi default: 1695465e1141STomohiro Kusumi printf("unsupported comp_level %d for %s\n", 1696465e1141STomohiro Kusumi comp_level_idx, comp_algo_str); 1697465e1141STomohiro Kusumi return EINVAL; 1698465e1141STomohiro Kusumi } 1699465e1141STomohiro Kusumi } 1700465e1141STomohiro Kusumi comp_level = HAMMER2_ENC_LEVEL(comp_level_idx); 1701465e1141STomohiro Kusumi printf("change %s to algo %d (%s) level %d\n", 1702465e1141STomohiro Kusumi p, comp_algo, comp_algo_str, comp_level_idx); 1703465e1141STomohiro Kusumi 1704465e1141STomohiro Kusumi while ((p = strchr(p, '/')) != NULL) { 1705465e1141STomohiro Kusumi *p++ = 0; /* NULL terminate name */ 1706465e1141STomohiro Kusumi vp = NULL; 1707465e1141STomohiro Kusumi error = hammer2_nresolve(dvp, &vp, name, strlen(name)); 1708465e1141STomohiro Kusumi if (error) 1709465e1141STomohiro Kusumi return error; 1710465e1141STomohiro Kusumi 1711465e1141STomohiro Kusumi ip = VTOI(vp); 1712465e1141STomohiro Kusumi assert(ip->meta.type == HAMMER2_OBJTYPE_DIRECTORY); 1713465e1141STomohiro Kusumi 1714465e1141STomohiro Kusumi dvp = vp; 1715465e1141STomohiro Kusumi name = p; 1716465e1141STomohiro Kusumi } 1717465e1141STomohiro Kusumi 1718465e1141STomohiro Kusumi error = hammer2_nresolve(dvp, &vp, name, strlen(name)); 1719465e1141STomohiro Kusumi if (error) 1720465e1141STomohiro Kusumi return error; 1721465e1141STomohiro Kusumi ip = VTOI(vp); 1722465e1141STomohiro Kusumi 1723465e1141STomohiro Kusumi bzero(&inode, sizeof(inode)); 1724465e1141STomohiro Kusumi error = hammer2_ioctl_inode_get(ip, &inode); 1725465e1141STomohiro Kusumi if (error) 1726465e1141STomohiro Kusumi return error; 1727465e1141STomohiro Kusumi 1728465e1141STomohiro Kusumi inode.flags |= HAMMER2IOC_INODE_FLAG_COMP; 1729465e1141STomohiro Kusumi inode.ip_data.meta.comp_algo = comp_algo | comp_level; 1730465e1141STomohiro Kusumi error = hammer2_ioctl_inode_set(ip, &inode); 1731465e1141STomohiro Kusumi if (error) 1732465e1141STomohiro Kusumi return error; 1733465e1141STomohiro Kusumi 1734465e1141STomohiro Kusumi free(o); 1735465e1141STomohiro Kusumi 1736465e1141STomohiro Kusumi return error; 1737465e1141STomohiro Kusumi } 1738465e1141STomohiro Kusumi 1739465e1141STomohiro Kusumi static int 1740a63188c8STomohiro Kusumi hammer2_bulkfree(struct m_vnode *vp) 1741a63188c8STomohiro Kusumi { 1742a63188c8STomohiro Kusumi hammer2_ioc_bulkfree_t bfi; 1743a63188c8STomohiro Kusumi size_t usermem; 1744a63188c8STomohiro Kusumi size_t usermem_size = sizeof(usermem); 1745a63188c8STomohiro Kusumi 1746a63188c8STomohiro Kusumi bzero(&bfi, sizeof(bfi)); 1747a63188c8STomohiro Kusumi usermem = 0; 1748a63188c8STomohiro Kusumi if (sysctlbyname("hw.usermem", &usermem, &usermem_size, NULL, 0) == 0) 1749a63188c8STomohiro Kusumi bfi.size = usermem / 16; 1750a63188c8STomohiro Kusumi else 1751a63188c8STomohiro Kusumi bfi.size = 0; 1752a63188c8STomohiro Kusumi if (bfi.size < 8192 * 1024) 1753a63188c8STomohiro Kusumi bfi.size = 8192 * 1024; 1754a63188c8STomohiro Kusumi 1755a63188c8STomohiro Kusumi return hammer2_ioctl_bulkfree_scan(VTOI(vp), &bfi); 1756a63188c8STomohiro Kusumi } 1757afa5234bSTomohiro Kusumi 1758afa5234bSTomohiro Kusumi static int 1759ac97ce60STomohiro Kusumi hammer2_destroy_path(struct m_vnode *dvp, const char *f) 1760917508cdSTomohiro Kusumi { 1761917508cdSTomohiro Kusumi hammer2_ioc_destroy_t destroy; 1762ac97ce60STomohiro Kusumi hammer2_inode_t *ip; 1763ac97ce60STomohiro Kusumi struct m_vnode *vp; 1764ac97ce60STomohiro Kusumi char *o, *p, *name; 1765b4807901STomohiro Kusumi int error; 1766917508cdSTomohiro Kusumi 176706d1ac82STomohiro Kusumi assert(strlen(f) > 0); 17686857f034STomohiro Kusumi o = p = name = strdup(f); 1769ac97ce60STomohiro Kusumi 17706857f034STomohiro Kusumi error = trim_slash(p); 17716857f034STomohiro Kusumi if (error) 17726857f034STomohiro Kusumi return error; 1773ac97ce60STomohiro Kusumi if (strlen(p) == 0) 1774ac97ce60STomohiro Kusumi return EINVAL; 1775ac97ce60STomohiro Kusumi 1776ac97ce60STomohiro Kusumi while ((p = strchr(p, '/')) != NULL) { 1777ac97ce60STomohiro Kusumi *p++ = 0; /* NULL terminate name */ 1778ac97ce60STomohiro Kusumi vp = NULL; 1779ac97ce60STomohiro Kusumi error = hammer2_nresolve(dvp, &vp, name, strlen(name)); 1780ac97ce60STomohiro Kusumi if (error) 1781ac97ce60STomohiro Kusumi return error; 1782ac97ce60STomohiro Kusumi 1783ac97ce60STomohiro Kusumi ip = VTOI(vp); 1784ac97ce60STomohiro Kusumi assert(ip->meta.type == HAMMER2_OBJTYPE_DIRECTORY); 1785ac97ce60STomohiro Kusumi 1786ac97ce60STomohiro Kusumi dvp = vp; 1787ac97ce60STomohiro Kusumi name = p; 1788ac97ce60STomohiro Kusumi } 1789ac97ce60STomohiro Kusumi 1790ba024da8STomohiro Kusumi /* XXX When does (or why does not) ioctl modify this inode ? */ 1791ba024da8STomohiro Kusumi hammer2_inode_modify(VTOI(dvp)); 1792ba024da8STomohiro Kusumi 1793917508cdSTomohiro Kusumi bzero(&destroy, sizeof(destroy)); 1794917508cdSTomohiro Kusumi destroy.cmd = HAMMER2_DELETE_FILE; 1795ac97ce60STomohiro Kusumi snprintf(destroy.path, sizeof(destroy.path), "%s", name); 1796917508cdSTomohiro Kusumi 1797917508cdSTomohiro Kusumi printf("%s\t", f); 1798917508cdSTomohiro Kusumi fflush(stdout); 1799917508cdSTomohiro Kusumi 1800ac97ce60STomohiro Kusumi error = hammer2_ioctl_destroy(VTOI(dvp), &destroy); 1801917508cdSTomohiro Kusumi if (error) 1802917508cdSTomohiro Kusumi printf("%s\n", strerror(error)); 1803917508cdSTomohiro Kusumi else 1804917508cdSTomohiro Kusumi printf("ok\n"); 1805ac97ce60STomohiro Kusumi free(o); 1806917508cdSTomohiro Kusumi 1807917508cdSTomohiro Kusumi return error; 1808917508cdSTomohiro Kusumi } 1809917508cdSTomohiro Kusumi 1810917508cdSTomohiro Kusumi static int 1811917508cdSTomohiro Kusumi hammer2_destroy_inum(struct m_vnode *vp, hammer2_tid_t inum) 1812917508cdSTomohiro Kusumi { 1813917508cdSTomohiro Kusumi hammer2_ioc_destroy_t destroy; 1814b4807901STomohiro Kusumi int error; 1815917508cdSTomohiro Kusumi 1816917508cdSTomohiro Kusumi bzero(&destroy, sizeof(destroy)); 1817917508cdSTomohiro Kusumi destroy.cmd = HAMMER2_DELETE_INUM; 1818917508cdSTomohiro Kusumi destroy.inum = inum; 1819917508cdSTomohiro Kusumi 1820917508cdSTomohiro Kusumi printf("%jd\t", (intmax_t)destroy.inum); 1821917508cdSTomohiro Kusumi fflush(stdout); 1822917508cdSTomohiro Kusumi 1823917508cdSTomohiro Kusumi error = hammer2_ioctl_destroy(VTOI(vp), &destroy); 1824917508cdSTomohiro Kusumi if (error) 1825917508cdSTomohiro Kusumi printf("%s\n", strerror(error)); 1826917508cdSTomohiro Kusumi else 1827917508cdSTomohiro Kusumi printf("ok\n"); 1828917508cdSTomohiro Kusumi 1829917508cdSTomohiro Kusumi return error; 1830917508cdSTomohiro Kusumi } 1831917508cdSTomohiro Kusumi 1832917508cdSTomohiro Kusumi static int 1833afa5234bSTomohiro Kusumi hammer2_growfs(struct m_vnode *vp, hammer2_off_t size) 1834afa5234bSTomohiro Kusumi { 1835afa5234bSTomohiro Kusumi hammer2_ioc_growfs_t growfs; 1836afa5234bSTomohiro Kusumi int error; 1837afa5234bSTomohiro Kusumi 1838afa5234bSTomohiro Kusumi bzero(&growfs, sizeof(growfs)); 1839afa5234bSTomohiro Kusumi growfs.size = size; 1840afa5234bSTomohiro Kusumi 1841afa5234bSTomohiro Kusumi error = hammer2_ioctl_growfs(VTOI(vp), &growfs, NULL); 1842afa5234bSTomohiro Kusumi if (!error) { 1843afa5234bSTomohiro Kusumi if (growfs.modified) 1844afa5234bSTomohiro Kusumi printf("grown to %016jx\n", (intmax_t)growfs.size); 1845afa5234bSTomohiro Kusumi else 1846afa5234bSTomohiro Kusumi printf("no size change - %016jx\n", 1847afa5234bSTomohiro Kusumi (intmax_t)growfs.size); 1848afa5234bSTomohiro Kusumi } 1849afa5234bSTomohiro Kusumi 1850afa5234bSTomohiro Kusumi return error; 1851afa5234bSTomohiro Kusumi } 18526857f034STomohiro Kusumi 18536857f034STomohiro Kusumi static void 18546857f034STomohiro Kusumi assert_trim_slash(const char *input, const char *expected) 18556857f034STomohiro Kusumi { 18566857f034STomohiro Kusumi char tmp[PATH_MAX]; 18576857f034STomohiro Kusumi int error; 18586857f034STomohiro Kusumi 18596857f034STomohiro Kusumi strlcpy(tmp, input, sizeof(tmp)); 18606857f034STomohiro Kusumi error = trim_slash(tmp); 18616857f034STomohiro Kusumi if (error) 18626857f034STomohiro Kusumi errx(1, "input \"%s\" error %d", input, error); 18636857f034STomohiro Kusumi 18646857f034STomohiro Kusumi if (strncmp(tmp, expected, sizeof(tmp))) 18656857f034STomohiro Kusumi errx(1, "input \"%s\" result \"%s\" vs expected \"%s\"", 18666857f034STomohiro Kusumi input, tmp, expected); 18676857f034STomohiro Kusumi } 18686857f034STomohiro Kusumi 18696857f034STomohiro Kusumi static void 18706857f034STomohiro Kusumi unittest_trim_slash(void) 18716857f034STomohiro Kusumi { 18726857f034STomohiro Kusumi assert_trim_slash("", ""); 18736857f034STomohiro Kusumi assert_trim_slash("/", ""); 18746857f034STomohiro Kusumi assert_trim_slash("//", ""); 18756857f034STomohiro Kusumi assert_trim_slash("///", ""); 18766857f034STomohiro Kusumi 18776857f034STomohiro Kusumi assert_trim_slash("makefs", "makefs"); 18786857f034STomohiro Kusumi assert_trim_slash("/makefs", "makefs"); 18796857f034STomohiro Kusumi assert_trim_slash("//makefs", "makefs"); 18806857f034STomohiro Kusumi assert_trim_slash("makefs/", "makefs"); 18816857f034STomohiro Kusumi assert_trim_slash("makefs//", "makefs"); 18826857f034STomohiro Kusumi assert_trim_slash("/makefs/", "makefs"); 18836857f034STomohiro Kusumi assert_trim_slash("//makefs//", "makefs"); 18846857f034STomohiro Kusumi 18856857f034STomohiro Kusumi assert_trim_slash("sys/vfs/hammer2", "sys/vfs/hammer2"); 18866857f034STomohiro Kusumi assert_trim_slash("/sys/vfs/hammer2", "sys/vfs/hammer2"); 18876857f034STomohiro Kusumi assert_trim_slash("//sys/vfs/hammer2", "sys/vfs/hammer2"); 18886857f034STomohiro Kusumi assert_trim_slash("///sys/vfs/hammer2", "sys/vfs/hammer2"); 18896857f034STomohiro Kusumi assert_trim_slash("sys/vfs/hammer2/", "sys/vfs/hammer2"); 18906857f034STomohiro Kusumi assert_trim_slash("sys/vfs/hammer2//", "sys/vfs/hammer2"); 18916857f034STomohiro Kusumi assert_trim_slash("sys/vfs/hammer2///", "sys/vfs/hammer2"); 18926857f034STomohiro Kusumi assert_trim_slash("/sys/vfs/hammer2/", "sys/vfs/hammer2"); 18936857f034STomohiro Kusumi assert_trim_slash("//sys//vfs//hammer2//", "sys/vfs/hammer2"); 18946857f034STomohiro Kusumi assert_trim_slash("///sys///vfs///hammer2///", "sys/vfs/hammer2"); 18956857f034STomohiro Kusumi 1896bca6a9a0STomohiro Kusumi APRINTF("success\n"); 18976857f034STomohiro Kusumi } 1898