16a6e350fSMatthew Dillon /* 26a6e350fSMatthew Dillon * Copyright (c) 2008 The DragonFly Project. All rights reserved. 36a6e350fSMatthew Dillon * 46a6e350fSMatthew Dillon * This code is derived from software contributed to The DragonFly Project 56a6e350fSMatthew Dillon * by Matthew Dillon <dillon@backplane.com> 66a6e350fSMatthew Dillon * 76a6e350fSMatthew Dillon * Redistribution and use in source and binary forms, with or without 86a6e350fSMatthew Dillon * modification, are permitted provided that the following conditions 96a6e350fSMatthew Dillon * are met: 106a6e350fSMatthew Dillon * 116a6e350fSMatthew Dillon * 1. Redistributions of source code must retain the above copyright 126a6e350fSMatthew Dillon * notice, this list of conditions and the following disclaimer. 136a6e350fSMatthew Dillon * 2. Redistributions in binary form must reproduce the above copyright 146a6e350fSMatthew Dillon * notice, this list of conditions and the following disclaimer in 156a6e350fSMatthew Dillon * the documentation and/or other materials provided with the 166a6e350fSMatthew Dillon * distribution. 176a6e350fSMatthew Dillon * 3. Neither the name of The DragonFly Project nor the names of its 186a6e350fSMatthew Dillon * contributors may be used to endorse or promote products derived 196a6e350fSMatthew Dillon * from this software without specific, prior written permission. 206a6e350fSMatthew Dillon * 216a6e350fSMatthew Dillon * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 226a6e350fSMatthew Dillon * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 236a6e350fSMatthew Dillon * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 246a6e350fSMatthew Dillon * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 256a6e350fSMatthew Dillon * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 266a6e350fSMatthew Dillon * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 276a6e350fSMatthew Dillon * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 286a6e350fSMatthew Dillon * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 296a6e350fSMatthew Dillon * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 306a6e350fSMatthew Dillon * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 316a6e350fSMatthew Dillon * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 326a6e350fSMatthew Dillon * SUCH DAMAGE. 336a6e350fSMatthew Dillon * 34bb8e52c0SThomas Nikolajsen * $DragonFly: src/sbin/hammer/cmd_cleanup.c,v 1.6 2008/10/07 22:28:41 thomas Exp $ 356a6e350fSMatthew Dillon */ 366a6e350fSMatthew Dillon /* 376a6e350fSMatthew Dillon * Clean up a specific HAMMER filesystem or all HAMMER filesystems. 386a6e350fSMatthew Dillon * 396a6e350fSMatthew Dillon * Each filesystem is expected to have a <mount>/snapshots directory. 406a6e350fSMatthew Dillon * No cleanup will be performed on any filesystem that does not. If 416a6e350fSMatthew Dillon * no filesystems are specified the 'df' program is run and any HAMMER 426a6e350fSMatthew Dillon * or null-mounted hammer PFS's are extracted. 436a6e350fSMatthew Dillon * 446a6e350fSMatthew Dillon * The snapshots directory may contain a config file called 'config'. If 456a6e350fSMatthew Dillon * no config file is present one will be created with the following 466a6e350fSMatthew Dillon * defaults: 476a6e350fSMatthew Dillon * 485e435c92SMatthew Dillon * snapshots 1d 60d (0d 0d for /tmp, /var/tmp, /usr/obj) 496a6e350fSMatthew Dillon * prune 1d 5m 50f13fea8bSSascha Wildner * rebalance 1d 5m 516a6e350fSMatthew Dillon * reblock 1d 5m 526a6e350fSMatthew Dillon * recopy 30d 5m 536a6e350fSMatthew Dillon * 546a6e350fSMatthew Dillon * All hammer commands create and maintain cycle files in the snapshots 556a6e350fSMatthew Dillon * directory. 566a6e350fSMatthew Dillon */ 576a6e350fSMatthew Dillon 586a6e350fSMatthew Dillon #include "hammer.h" 596a6e350fSMatthew Dillon 60c453712aSMatthew Dillon struct didpfs { 61c453712aSMatthew Dillon struct didpfs *next; 62c453712aSMatthew Dillon uuid_t uuid; 63c453712aSMatthew Dillon }; 64c453712aSMatthew Dillon 656a6e350fSMatthew Dillon static void do_cleanup(const char *path); 6683f2a3aaSMatthew Dillon static void config_init(const char *path, struct hammer_ioc_config *config); 6783f2a3aaSMatthew Dillon static void migrate_config(FILE *fp, struct hammer_ioc_config *config); 6883f2a3aaSMatthew Dillon static void migrate_snapshots(int fd, const char *snapshots_path); 6983f2a3aaSMatthew Dillon static void migrate_one_snapshot(int fd, const char *fpath, 7083f2a3aaSMatthew Dillon struct hammer_ioc_snapshot *snapshot); 716a6e350fSMatthew Dillon static int strtosecs(char *ptr); 726a6e350fSMatthew Dillon static const char *dividing_slash(const char *path); 736a6e350fSMatthew Dillon static int check_period(const char *snapshots_path, const char *cmd, int arg1, 746a6e350fSMatthew Dillon time_t *savep); 756a6e350fSMatthew Dillon static void save_period(const char *snapshots_path, const char *cmd, 766a6e350fSMatthew Dillon time_t savet); 7783f2a3aaSMatthew Dillon static int check_softlinks(int fd, int new_config, const char *snapshots_path); 7883f2a3aaSMatthew Dillon static void cleanup_softlinks(int fd, int new_config, 7983f2a3aaSMatthew Dillon const char *snapshots_path, int arg2, char *arg3); 80ff1c9800SMatthew Dillon static int check_expired(const char *fpath, int arg2); 816a6e350fSMatthew Dillon 82b5ec5ad4SMatthew Dillon static int create_snapshot(const char *path, const char *snapshots_path); 830b8bd7daSMatthew Dillon static int cleanup_rebalance(const char *path, const char *snapshots_path, 840b8bd7daSMatthew Dillon int arg1, int arg2); 856a6e350fSMatthew Dillon static int cleanup_prune(const char *path, const char *snapshots_path, 86c6c298a7SMatthew Dillon int arg1, int arg2, int snapshots_disabled); 876a6e350fSMatthew Dillon static int cleanup_reblock(const char *path, const char *snapshots_path, 886a6e350fSMatthew Dillon int arg1, int arg2); 896a6e350fSMatthew Dillon static int cleanup_recopy(const char *path, const char *snapshots_path, 906a6e350fSMatthew Dillon int arg1, int arg2); 916a6e350fSMatthew Dillon 926a6e350fSMatthew Dillon static void runcmd(int *resp, const char *ctl, ...); 936a6e350fSMatthew Dillon 94b5ec5ad4SMatthew Dillon /* 95b5ec5ad4SMatthew Dillon * WARNING: Do not make the SNAPSHOTS_BASE "/var/snapshots" because 96b5ec5ad4SMatthew Dillon * it will interfere with the older HAMMER VERS < 3 snapshots directory 97b5ec5ad4SMatthew Dillon * for the /var PFS. 98b5ec5ad4SMatthew Dillon */ 99b5ec5ad4SMatthew Dillon #define SNAPSHOTS_BASE "/var/hammer" /* HAMMER VERS >= 3 */ 1006a6e350fSMatthew Dillon #define WS " \t\r\n" 1016a6e350fSMatthew Dillon 102c453712aSMatthew Dillon struct didpfs *FirstPFS; 1036a6e350fSMatthew Dillon 1046a6e350fSMatthew Dillon void 1056a6e350fSMatthew Dillon hammer_cmd_cleanup(char **av, int ac) 1066a6e350fSMatthew Dillon { 107eac446c5SMatthew Dillon char *fstype, *fs, *path; 108eac446c5SMatthew Dillon struct statfs *stfsbuf; 109eac446c5SMatthew Dillon int mntsize, i; 1106a6e350fSMatthew Dillon 1116a6e350fSMatthew Dillon tzset(); 1126a6e350fSMatthew Dillon if (ac == 0) { 113eac446c5SMatthew Dillon mntsize = getmntinfo(&stfsbuf, MNT_NOWAIT); 114eac446c5SMatthew Dillon if (mntsize > 0) { 115eac446c5SMatthew Dillon for (i=0; i < mntsize; i++) { 116eac446c5SMatthew Dillon /* 117eac446c5SMatthew Dillon * We will cleanup in the case fstype is hammer. 118eac446c5SMatthew Dillon * If we have null-mounted PFS, we check the 119eac446c5SMatthew Dillon * mount source. If it looks like a PFS, we 120eac446c5SMatthew Dillon * proceed to cleanup also. 121eac446c5SMatthew Dillon */ 122eac446c5SMatthew Dillon fstype = stfsbuf[i].f_fstypename; 123eac446c5SMatthew Dillon fs = stfsbuf[i].f_mntfromname; 124eac446c5SMatthew Dillon if ((strcmp(fstype, "hammer") == 0) || 125eac446c5SMatthew Dillon ((strcmp(fstype, "null") == 0) && 126cb3c760cSMatthew Dillon (strstr(fs, "/@@0x") != NULL || 127cb3c760cSMatthew Dillon strstr(fs, "/@@-1") != NULL))) { 128eac446c5SMatthew Dillon path = stfsbuf[i].f_mntonname; 1296a6e350fSMatthew Dillon do_cleanup(path); 1306a6e350fSMatthew Dillon } 131574066d3SMatthew Dillon } 132eac446c5SMatthew Dillon } 133eac446c5SMatthew Dillon 1346a6e350fSMatthew Dillon } else { 1356a6e350fSMatthew Dillon while (ac) { 1366a6e350fSMatthew Dillon do_cleanup(*av); 1376a6e350fSMatthew Dillon --ac; 1386a6e350fSMatthew Dillon ++av; 1396a6e350fSMatthew Dillon } 1406a6e350fSMatthew Dillon } 1416a6e350fSMatthew Dillon } 1426a6e350fSMatthew Dillon 1436a6e350fSMatthew Dillon static 1446a6e350fSMatthew Dillon void 1456a6e350fSMatthew Dillon do_cleanup(const char *path) 1466a6e350fSMatthew Dillon { 1476a6e350fSMatthew Dillon struct hammer_ioc_pseudofs_rw pfs; 14883f2a3aaSMatthew Dillon struct hammer_ioc_config config; 14983f2a3aaSMatthew Dillon struct hammer_ioc_version version; 1506a6e350fSMatthew Dillon union hammer_ioc_mrecord_any mrec_tmp; 1516a6e350fSMatthew Dillon char *snapshots_path; 1526a6e350fSMatthew Dillon char *config_path; 1536a6e350fSMatthew Dillon struct stat st; 1546a6e350fSMatthew Dillon char *cmd; 1556a6e350fSMatthew Dillon char *ptr; 1566a6e350fSMatthew Dillon int arg1; 1576a6e350fSMatthew Dillon int arg2; 1585e435c92SMatthew Dillon char *arg3; 1596a6e350fSMatthew Dillon time_t savet; 1606a6e350fSMatthew Dillon char buf[256]; 16183f2a3aaSMatthew Dillon char *cbase; 16283f2a3aaSMatthew Dillon char *cptr; 1636a6e350fSMatthew Dillon FILE *fp; 164c453712aSMatthew Dillon struct didpfs *didpfs; 165c6c298a7SMatthew Dillon int snapshots_disabled = 0; 166c6c298a7SMatthew Dillon int prune_warning = 0; 16783f2a3aaSMatthew Dillon int new_config = 0; 168b5ec5ad4SMatthew Dillon int snapshots_from_pfs = 0; 1696a6e350fSMatthew Dillon int fd; 1706a6e350fSMatthew Dillon int r; 1710b8bd7daSMatthew Dillon int found_rebal = 0; 1726a6e350fSMatthew Dillon 1736a6e350fSMatthew Dillon bzero(&pfs, sizeof(pfs)); 1746a6e350fSMatthew Dillon bzero(&mrec_tmp, sizeof(mrec_tmp)); 1756a6e350fSMatthew Dillon pfs.ondisk = &mrec_tmp.pfs.pfsd; 1766a6e350fSMatthew Dillon pfs.bytes = sizeof(mrec_tmp.pfs.pfsd); 1776a6e350fSMatthew Dillon pfs.pfs_id = -1; 1786a6e350fSMatthew Dillon 1796a6e350fSMatthew Dillon printf("cleanup %-20s -", path); 1806a6e350fSMatthew Dillon fd = open(path, O_RDONLY); 1816a6e350fSMatthew Dillon if (fd < 0) { 1826a6e350fSMatthew Dillon printf(" unable to access directory: %s\n", strerror(errno)); 1836a6e350fSMatthew Dillon return; 1846a6e350fSMatthew Dillon } 18583f2a3aaSMatthew Dillon if (ioctl(fd, HAMMERIOC_GET_PSEUDOFS, &pfs) < 0) { 1866a6e350fSMatthew Dillon printf(" not a HAMMER filesystem: %s\n", strerror(errno)); 18783f2a3aaSMatthew Dillon close(fd); 1886a6e350fSMatthew Dillon return; 1896a6e350fSMatthew Dillon } 1906a6e350fSMatthew Dillon if (pfs.version != HAMMER_IOC_PSEUDOFS_VERSION) { 1916a6e350fSMatthew Dillon printf(" unrecognized HAMMER version\n"); 19283f2a3aaSMatthew Dillon close(fd); 1936a6e350fSMatthew Dillon return; 1946a6e350fSMatthew Dillon } 19583f2a3aaSMatthew Dillon bzero(&version, sizeof(version)); 19683f2a3aaSMatthew Dillon if (ioctl(fd, HAMMERIOC_GET_VERSION, &version) < 0) { 19783f2a3aaSMatthew Dillon printf(" HAMMER filesystem but couldn't retrieve version!\n"); 19883f2a3aaSMatthew Dillon close(fd); 19983f2a3aaSMatthew Dillon return; 20083f2a3aaSMatthew Dillon } 20183f2a3aaSMatthew Dillon 20283f2a3aaSMatthew Dillon bzero(&config, sizeof(config)); 20383f2a3aaSMatthew Dillon if (version.cur_version >= 3) { 20483f2a3aaSMatthew Dillon if (ioctl(fd, HAMMERIOC_GET_CONFIG, &config) == 0 && 20583f2a3aaSMatthew Dillon config.head.error == 0) { 20683f2a3aaSMatthew Dillon new_config = 1; 20783f2a3aaSMatthew Dillon } 20883f2a3aaSMatthew Dillon } 2096a6e350fSMatthew Dillon 2106a6e350fSMatthew Dillon /* 2116a6e350fSMatthew Dillon * Make sure we have not already handled this PFS. Several nullfs 2126a6e350fSMatthew Dillon * mounts might alias the same PFS. 2136a6e350fSMatthew Dillon */ 214c453712aSMatthew Dillon for (didpfs = FirstPFS; didpfs; didpfs = didpfs->next) { 215c453712aSMatthew Dillon if (bcmp(&didpfs->uuid, &mrec_tmp.pfs.pfsd.unique_uuid, sizeof(uuid_t)) == 0) { 216bb8e52c0SThomas Nikolajsen printf(" PFS #%d already handled\n", pfs.pfs_id); 21783f2a3aaSMatthew Dillon close(fd); 2186a6e350fSMatthew Dillon return; 2196a6e350fSMatthew Dillon } 220c453712aSMatthew Dillon } 221c453712aSMatthew Dillon didpfs = malloc(sizeof(*didpfs)); 222c453712aSMatthew Dillon didpfs->next = FirstPFS; 223c453712aSMatthew Dillon FirstPFS = didpfs; 224c453712aSMatthew Dillon didpfs->uuid = mrec_tmp.pfs.pfsd.unique_uuid; 2256a6e350fSMatthew Dillon 2266a6e350fSMatthew Dillon /* 227b5ec5ad4SMatthew Dillon * Calculate the old snapshots directory for HAMMER VERSION < 3 228b5ec5ad4SMatthew Dillon * 229b5ec5ad4SMatthew Dillon * If the directory is explicitly specified in the PFS config 230b5ec5ad4SMatthew Dillon * we flag it and will not migrate it later. 231ff1c9800SMatthew Dillon */ 232ff1c9800SMatthew Dillon if (mrec_tmp.pfs.pfsd.snapshots[0] == '/') { 233ff1c9800SMatthew Dillon asprintf(&snapshots_path, "%s", mrec_tmp.pfs.pfsd.snapshots); 234b5ec5ad4SMatthew Dillon snapshots_from_pfs = 1; 235ff1c9800SMatthew Dillon } else if (mrec_tmp.pfs.pfsd.snapshots[0]) { 236ff1c9800SMatthew Dillon printf(" WARNING: pfs-slave's snapshots dir is not absolute\n"); 23783f2a3aaSMatthew Dillon close(fd); 238ff1c9800SMatthew Dillon return; 239ff1c9800SMatthew Dillon } else if (mrec_tmp.pfs.pfsd.mirror_flags & HAMMER_PFSD_SLAVE) { 240ff1c9800SMatthew Dillon printf(" WARNING: must configure snapshot dir for PFS slave\n"); 241ff1c9800SMatthew Dillon printf("\tWe suggest <fs>/var/slaves/<name> where " 242ff1c9800SMatthew Dillon "<fs> is the base HAMMER fs\n"); 243bb8e52c0SThomas Nikolajsen printf("\tcontaining the slave\n"); 24483f2a3aaSMatthew Dillon close(fd); 245ff1c9800SMatthew Dillon return; 246ff1c9800SMatthew Dillon } else { 247ff1c9800SMatthew Dillon asprintf(&snapshots_path, 248ff1c9800SMatthew Dillon "%s%ssnapshots", path, dividing_slash(path)); 249ff1c9800SMatthew Dillon } 250ff1c9800SMatthew Dillon 251ff1c9800SMatthew Dillon /* 252b5ec5ad4SMatthew Dillon * Check for old-style config file 2536a6e350fSMatthew Dillon */ 2546a6e350fSMatthew Dillon asprintf(&config_path, "%s/config", snapshots_path); 2556a6e350fSMatthew Dillon fp = fopen(config_path, "r"); 25683f2a3aaSMatthew Dillon 25783f2a3aaSMatthew Dillon /* 25883f2a3aaSMatthew Dillon * Handle upgrades to hammer version 3, move the config 25983f2a3aaSMatthew Dillon * file into meta-data. 26083f2a3aaSMatthew Dillon * 26183f2a3aaSMatthew Dillon * For the old config read the file into the config structure, 26283f2a3aaSMatthew Dillon * we will parse it out of the config structure regardless. 26383f2a3aaSMatthew Dillon */ 26483f2a3aaSMatthew Dillon if (version.cur_version >= 3) { 26583f2a3aaSMatthew Dillon if (fp) { 26683f2a3aaSMatthew Dillon printf("(migrating) "); 26783f2a3aaSMatthew Dillon fflush(stdout); 26883f2a3aaSMatthew Dillon migrate_config(fp, &config); 26983f2a3aaSMatthew Dillon migrate_snapshots(fd, snapshots_path); 27083f2a3aaSMatthew Dillon fclose(fp); 27183f2a3aaSMatthew Dillon if (ioctl(fd, HAMMERIOC_SET_CONFIG, &config) < 0) { 27283f2a3aaSMatthew Dillon printf(" cannot init meta-data config!\n"); 27383f2a3aaSMatthew Dillon close(fd); 2746a6e350fSMatthew Dillon return; 2756a6e350fSMatthew Dillon } 27683f2a3aaSMatthew Dillon remove(config_path); 27783f2a3aaSMatthew Dillon } else if (new_config == 0) { 27883f2a3aaSMatthew Dillon config_init(path, &config); 27983f2a3aaSMatthew Dillon if (ioctl(fd, HAMMERIOC_SET_CONFIG, &config) < 0) { 28083f2a3aaSMatthew Dillon printf(" cannot init meta-data config!\n"); 28183f2a3aaSMatthew Dillon close(fd); 28283f2a3aaSMatthew Dillon return; 28383f2a3aaSMatthew Dillon } 28483f2a3aaSMatthew Dillon } 28583f2a3aaSMatthew Dillon new_config = 1; 28683f2a3aaSMatthew Dillon } else { 287b5ec5ad4SMatthew Dillon /* 288b5ec5ad4SMatthew Dillon * Create missing snapshots directory for HAMMER VERSION < 3 289b5ec5ad4SMatthew Dillon */ 290b5ec5ad4SMatthew Dillon if (stat(snapshots_path, &st) < 0) { 291b5ec5ad4SMatthew Dillon if (mkdir(snapshots_path, 0755) != 0) { 292b5ec5ad4SMatthew Dillon free(snapshots_path); 293b5ec5ad4SMatthew Dillon printf(" unable to create snapshot dir \"%s\": %s\n", 294b5ec5ad4SMatthew Dillon snapshots_path, strerror(errno)); 295b5ec5ad4SMatthew Dillon close(fd); 296b5ec5ad4SMatthew Dillon return; 297b5ec5ad4SMatthew Dillon } 298b5ec5ad4SMatthew Dillon } 299b5ec5ad4SMatthew Dillon 300b5ec5ad4SMatthew Dillon /* 301b5ec5ad4SMatthew Dillon * Create missing config file for HAMMER VERSION < 3 302b5ec5ad4SMatthew Dillon */ 30383f2a3aaSMatthew Dillon if (fp == NULL) { 30483f2a3aaSMatthew Dillon config_init(path, &config); 30583f2a3aaSMatthew Dillon fp = fopen(config_path, "w"); 30683f2a3aaSMatthew Dillon if (fp) { 30783f2a3aaSMatthew Dillon fwrite(config.config.text, 1, 30883f2a3aaSMatthew Dillon strlen(config.config.text), fp); 30983f2a3aaSMatthew Dillon fclose(fp); 31083f2a3aaSMatthew Dillon } 31183f2a3aaSMatthew Dillon } else { 31283f2a3aaSMatthew Dillon migrate_config(fp, &config); 31383f2a3aaSMatthew Dillon fclose(fp); 31483f2a3aaSMatthew Dillon } 31583f2a3aaSMatthew Dillon } 3166a6e350fSMatthew Dillon 317b5ec5ad4SMatthew Dillon /* 318b5ec5ad4SMatthew Dillon * If snapshots_from_pfs is not set we calculate the new snapshots 319b5ec5ad4SMatthew Dillon * directory default (in /var) for HAMMER VERSION >= 3 and migrate 320b5ec5ad4SMatthew Dillon * the old snapshots directory over. 321b5ec5ad4SMatthew Dillon * 322b5ec5ad4SMatthew Dillon * People who have set an explicit snapshots directory will have 323b5ec5ad4SMatthew Dillon * to migrate the data manually into /var/hammer, or not bother at 324b5ec5ad4SMatthew Dillon * all. People running slaves may wish to migrate it and then 325b5ec5ad4SMatthew Dillon * clear the snapshots specification in the PFS config for the 326b5ec5ad4SMatthew Dillon * slave. 327b5ec5ad4SMatthew Dillon */ 328b5ec5ad4SMatthew Dillon if (new_config && snapshots_from_pfs == 0) { 329b5ec5ad4SMatthew Dillon char *npath; 330b5ec5ad4SMatthew Dillon 331b5ec5ad4SMatthew Dillon assert(path[0] == '/'); 332b5ec5ad4SMatthew Dillon if (strcmp(path, "/") == 0) 333b5ec5ad4SMatthew Dillon asprintf(&npath, "%s/root", SNAPSHOTS_BASE); 334b5ec5ad4SMatthew Dillon else 335b5ec5ad4SMatthew Dillon asprintf(&npath, "%s/%s", SNAPSHOTS_BASE, path + 1); 336b5ec5ad4SMatthew Dillon if (stat(npath, &st) < 0 && errno == ENOENT) { 337b5ec5ad4SMatthew Dillon if (stat(snapshots_path, &st) < 0 && errno == ENOENT) { 338b5ec5ad4SMatthew Dillon printf(" HAMMER UPGRADE: Creating snapshots\n" 339b5ec5ad4SMatthew Dillon "\tCreating snapshots in %s\n", 340b5ec5ad4SMatthew Dillon npath); 341b5ec5ad4SMatthew Dillon runcmd(&r, "mkdir -p %s", npath); 342b5ec5ad4SMatthew Dillon } else { 343b5ec5ad4SMatthew Dillon printf(" HAMMER UPGRADE: Moving snapshots\n" 344b5ec5ad4SMatthew Dillon "\tMoving snapshots from %s to %s\n", 345b5ec5ad4SMatthew Dillon snapshots_path, npath); 346b5ec5ad4SMatthew Dillon runcmd(&r, "mkdir -p %s", npath); 347b5ec5ad4SMatthew Dillon runcmd(&r, "cpdup %s %s", snapshots_path, npath); 348b5ec5ad4SMatthew Dillon if (r != 0) { 349b5ec5ad4SMatthew Dillon printf("Unable to move snapshots directory!\n"); 350b5ec5ad4SMatthew Dillon printf("Please fix this critical error.\n"); 351b5ec5ad4SMatthew Dillon printf("Aborting cleanup of %s\n", path); 352b5ec5ad4SMatthew Dillon close(fd); 353b5ec5ad4SMatthew Dillon return; 354b5ec5ad4SMatthew Dillon } 355b5ec5ad4SMatthew Dillon runcmd(&r, "rm -rf %s", snapshots_path); 356b5ec5ad4SMatthew Dillon } 357b5ec5ad4SMatthew Dillon } 358b5ec5ad4SMatthew Dillon free(snapshots_path); 359b5ec5ad4SMatthew Dillon snapshots_path = npath; 360b5ec5ad4SMatthew Dillon } 361b5ec5ad4SMatthew Dillon 362b5ec5ad4SMatthew Dillon /* 363b5ec5ad4SMatthew Dillon * Lock the PFS. fd is the base directory of the mounted PFS. 364b5ec5ad4SMatthew Dillon */ 36583f2a3aaSMatthew Dillon if (flock(fd, LOCK_EX|LOCK_NB) == -1) { 3665bd5f172SSimon Schubert if (errno == EWOULDBLOCK) 3675bd5f172SSimon Schubert printf(" PFS #%d locked by other process\n", pfs.pfs_id); 3685bd5f172SSimon Schubert else 3695bd5f172SSimon Schubert printf(" can not lock %s: %s\n", config_path, strerror(errno)); 37083f2a3aaSMatthew Dillon close(fd); 3715bd5f172SSimon Schubert return; 3725bd5f172SSimon Schubert } 3735bd5f172SSimon Schubert 374ff1c9800SMatthew Dillon printf(" handle PFS #%d using %s\n", pfs.pfs_id, snapshots_path); 3756a6e350fSMatthew Dillon 3766a6e350fSMatthew Dillon /* 3776a6e350fSMatthew Dillon * Process the config file 3786a6e350fSMatthew Dillon */ 37983f2a3aaSMatthew Dillon cbase = config.config.text; 38083f2a3aaSMatthew Dillon 38183f2a3aaSMatthew Dillon while ((cptr = strchr(cbase, '\n')) != NULL) { 38283f2a3aaSMatthew Dillon bcopy(cbase, buf, cptr - cbase); 38383f2a3aaSMatthew Dillon buf[cptr - cbase] = 0; 38483f2a3aaSMatthew Dillon cbase = cptr + 1; 38583f2a3aaSMatthew Dillon 3866a6e350fSMatthew Dillon cmd = strtok(buf, WS); 3876a6e350fSMatthew Dillon arg1 = 0; 3886a6e350fSMatthew Dillon arg2 = 0; 3895e435c92SMatthew Dillon arg3 = NULL; 3906a6e350fSMatthew Dillon if ((ptr = strtok(NULL, WS)) != NULL) { 3916a6e350fSMatthew Dillon arg1 = strtosecs(ptr); 3925e435c92SMatthew Dillon if ((ptr = strtok(NULL, WS)) != NULL) { 3936a6e350fSMatthew Dillon arg2 = strtosecs(ptr); 3945e435c92SMatthew Dillon arg3 = strtok(NULL, WS); 3955e435c92SMatthew Dillon } 3966a6e350fSMatthew Dillon } 3976a6e350fSMatthew Dillon 3986a6e350fSMatthew Dillon printf("%20s - ", cmd); 3996a6e350fSMatthew Dillon fflush(stdout); 4006a6e350fSMatthew Dillon 4016a6e350fSMatthew Dillon r = 1; 4026a6e350fSMatthew Dillon if (strcmp(cmd, "snapshots") == 0) { 4035e435c92SMatthew Dillon if (arg1 == 0) { 40483f2a3aaSMatthew Dillon if (arg2 && 40583f2a3aaSMatthew Dillon check_softlinks(fd, new_config, 40683f2a3aaSMatthew Dillon snapshots_path)) { 4075e435c92SMatthew Dillon printf("only removing old snapshots\n"); 4085e435c92SMatthew Dillon prune_warning = 1; 40983f2a3aaSMatthew Dillon cleanup_softlinks(fd, new_config, 41083f2a3aaSMatthew Dillon snapshots_path, 4115e435c92SMatthew Dillon arg2, arg3); 4125e435c92SMatthew Dillon } else { 4135e435c92SMatthew Dillon printf("disabled\n"); 4145e435c92SMatthew Dillon snapshots_disabled = 1; 4155e435c92SMatthew Dillon } 4165e435c92SMatthew Dillon } else 4176a6e350fSMatthew Dillon if (check_period(snapshots_path, cmd, arg1, &savet)) { 4186a6e350fSMatthew Dillon printf("run\n"); 41983f2a3aaSMatthew Dillon cleanup_softlinks(fd, new_config, 42083f2a3aaSMatthew Dillon snapshots_path, 4215e435c92SMatthew Dillon arg2, arg3); 422b5ec5ad4SMatthew Dillon r = create_snapshot(path, snapshots_path); 4236a6e350fSMatthew Dillon } else { 4246a6e350fSMatthew Dillon printf("skip\n"); 4256a6e350fSMatthew Dillon } 4265e435c92SMatthew Dillon } else if (arg1 == 0) { 4275e435c92SMatthew Dillon /* 4285e435c92SMatthew Dillon * The commands following this check can't handle 4295e435c92SMatthew Dillon * a period of 0, so call the feature disabled and 4305e435c92SMatthew Dillon * ignore the directive. 4315e435c92SMatthew Dillon */ 4325e435c92SMatthew Dillon printf("disabled\n"); 4336a6e350fSMatthew Dillon } else if (strcmp(cmd, "prune") == 0) { 4346a6e350fSMatthew Dillon if (check_period(snapshots_path, cmd, arg1, &savet)) { 4355e435c92SMatthew Dillon if (prune_warning) { 4365e435c92SMatthew Dillon printf("run - WARNING snapshot " 4375e435c92SMatthew Dillon "softlinks present " 438226f3799SThomas Nikolajsen "but snapshots disabled\n"); 4395e435c92SMatthew Dillon } else { 440c6c298a7SMatthew Dillon printf("run\n"); 4415e435c92SMatthew Dillon } 4426a6e350fSMatthew Dillon r = cleanup_prune(path, snapshots_path, 443c6c298a7SMatthew Dillon arg1, arg2, snapshots_disabled); 4446a6e350fSMatthew Dillon } else { 4456a6e350fSMatthew Dillon printf("skip\n"); 4466a6e350fSMatthew Dillon } 4470b8bd7daSMatthew Dillon } else if (strcmp(cmd, "rebalance") == 0) { 4480b8bd7daSMatthew Dillon found_rebal = 1; 4490b8bd7daSMatthew Dillon if (check_period(snapshots_path, cmd, arg1, &savet)) { 4500b8bd7daSMatthew Dillon printf("run"); 4510b8bd7daSMatthew Dillon fflush(stdout); 4520b8bd7daSMatthew Dillon if (VerboseOpt) 4530b8bd7daSMatthew Dillon printf("\n"); 4540b8bd7daSMatthew Dillon r = cleanup_rebalance(path, snapshots_path, 4550b8bd7daSMatthew Dillon arg1, arg2); 4560b8bd7daSMatthew Dillon } else { 4570b8bd7daSMatthew Dillon printf("skip\n"); 4580b8bd7daSMatthew Dillon } 4596a6e350fSMatthew Dillon } else if (strcmp(cmd, "reblock") == 0) { 4606a6e350fSMatthew Dillon if (check_period(snapshots_path, cmd, arg1, &savet)) { 4616a6e350fSMatthew Dillon printf("run"); 4626a6e350fSMatthew Dillon fflush(stdout); 4636a6e350fSMatthew Dillon if (VerboseOpt) 4646a6e350fSMatthew Dillon printf("\n"); 4656a6e350fSMatthew Dillon r = cleanup_reblock(path, snapshots_path, 4666a6e350fSMatthew Dillon arg1, arg2); 4676a6e350fSMatthew Dillon } else { 4686a6e350fSMatthew Dillon printf("skip\n"); 4696a6e350fSMatthew Dillon } 4706a6e350fSMatthew Dillon } else if (strcmp(cmd, "recopy") == 0) { 4716a6e350fSMatthew Dillon if (check_period(snapshots_path, cmd, arg1, &savet)) { 4726a6e350fSMatthew Dillon printf("run"); 4736a6e350fSMatthew Dillon fflush(stdout); 4746a6e350fSMatthew Dillon if (VerboseOpt) 4756a6e350fSMatthew Dillon printf("\n"); 4766a6e350fSMatthew Dillon r = cleanup_recopy(path, snapshots_path, 4776a6e350fSMatthew Dillon arg1, arg2); 4786a6e350fSMatthew Dillon } else { 4796a6e350fSMatthew Dillon printf("skip\n"); 4806a6e350fSMatthew Dillon } 4816a6e350fSMatthew Dillon } else { 4826a6e350fSMatthew Dillon printf("unknown directive\n"); 4836a6e350fSMatthew Dillon r = 1; 4846a6e350fSMatthew Dillon } 4856a6e350fSMatthew Dillon if (r == 0) 4866a6e350fSMatthew Dillon save_period(snapshots_path, cmd, savet); 4876a6e350fSMatthew Dillon } 4880b8bd7daSMatthew Dillon 4890b8bd7daSMatthew Dillon /* 49083f2a3aaSMatthew Dillon * Add new rebalance feature if the config doesn't have it. 491b5ec5ad4SMatthew Dillon * (old style config only). 4920b8bd7daSMatthew Dillon */ 49383f2a3aaSMatthew Dillon if (new_config == 0 && found_rebal == 0) { 4940b8bd7daSMatthew Dillon if ((fp = fopen(config_path, "r+")) != NULL) { 4950b8bd7daSMatthew Dillon fseek(fp, 0L, 2); 4960b8bd7daSMatthew Dillon fprintf(fp, "rebalance 1d 5m\n"); 4970b8bd7daSMatthew Dillon fclose(fp); 4980b8bd7daSMatthew Dillon } 4990b8bd7daSMatthew Dillon } 50083f2a3aaSMatthew Dillon 50183f2a3aaSMatthew Dillon /* 50283f2a3aaSMatthew Dillon * Cleanup, and delay a little 50383f2a3aaSMatthew Dillon */ 50483f2a3aaSMatthew Dillon close(fd); 5056a6e350fSMatthew Dillon usleep(1000); 5066a6e350fSMatthew Dillon } 5076a6e350fSMatthew Dillon 50883f2a3aaSMatthew Dillon /* 50983f2a3aaSMatthew Dillon * Initialize new config data (new or old style) 51083f2a3aaSMatthew Dillon */ 51183f2a3aaSMatthew Dillon static void 51283f2a3aaSMatthew Dillon config_init(const char *path, struct hammer_ioc_config *config) 51383f2a3aaSMatthew Dillon { 51483f2a3aaSMatthew Dillon const char *snapshots; 51583f2a3aaSMatthew Dillon 51683f2a3aaSMatthew Dillon if (strcmp(path, "/tmp") == 0 || 51783f2a3aaSMatthew Dillon strcmp(path, "/var/tmp") == 0 || 51883f2a3aaSMatthew Dillon strcmp(path, "/usr/obj") == 0) { 51983f2a3aaSMatthew Dillon snapshots = "snapshots 0d 0d\n"; 52083f2a3aaSMatthew Dillon } else { 52183f2a3aaSMatthew Dillon snapshots = "snapshots 1d 60d\n"; 52283f2a3aaSMatthew Dillon } 52383f2a3aaSMatthew Dillon bzero(config->config.text, sizeof(config->config.text)); 52483f2a3aaSMatthew Dillon snprintf(config->config.text, sizeof(config->config.text) - 1, "%s%s", 52583f2a3aaSMatthew Dillon snapshots, 52683f2a3aaSMatthew Dillon "prune 1d 5m\n" 52783f2a3aaSMatthew Dillon "rebalance 1d 5m\n" 52883f2a3aaSMatthew Dillon "reblock 1d 5m\n" 52983f2a3aaSMatthew Dillon "recopy 30d 10m\n" 53083f2a3aaSMatthew Dillon "rebalance 1d 5m\n"); 53183f2a3aaSMatthew Dillon } 53283f2a3aaSMatthew Dillon 53383f2a3aaSMatthew Dillon /* 53483f2a3aaSMatthew Dillon * Migrate configuration data from the old snapshots/config 53583f2a3aaSMatthew Dillon * file to the new mata-data format. 53683f2a3aaSMatthew Dillon */ 53783f2a3aaSMatthew Dillon static void 53883f2a3aaSMatthew Dillon migrate_config(FILE *fp, struct hammer_ioc_config *config) 53983f2a3aaSMatthew Dillon { 54083f2a3aaSMatthew Dillon int n; 54183f2a3aaSMatthew Dillon 54283f2a3aaSMatthew Dillon n = fread(config->config.text, 1, sizeof(config->config.text) - 1, fp); 54383f2a3aaSMatthew Dillon if (n >= 0) 54483f2a3aaSMatthew Dillon bzero(config->config.text + n, sizeof(config->config.text) - n); 54583f2a3aaSMatthew Dillon } 54683f2a3aaSMatthew Dillon 54783f2a3aaSMatthew Dillon /* 54883f2a3aaSMatthew Dillon * Migrate snapshot softlinks in the snapshots directory to the 54983f2a3aaSMatthew Dillon * new meta-data format. The softlinks are left intact, but 55083f2a3aaSMatthew Dillon * this way the pruning code won't lose track of them if you 55183f2a3aaSMatthew Dillon * happen to blow away the snapshots directory. 55283f2a3aaSMatthew Dillon */ 55383f2a3aaSMatthew Dillon static void 55483f2a3aaSMatthew Dillon migrate_snapshots(int fd, const char *snapshots_path) 55583f2a3aaSMatthew Dillon { 55683f2a3aaSMatthew Dillon struct hammer_ioc_snapshot snapshot; 55783f2a3aaSMatthew Dillon struct dirent *den; 55883f2a3aaSMatthew Dillon struct stat st; 55983f2a3aaSMatthew Dillon DIR *dir; 56083f2a3aaSMatthew Dillon char *fpath; 56183f2a3aaSMatthew Dillon 56283f2a3aaSMatthew Dillon bzero(&snapshot, sizeof(snapshot)); 56383f2a3aaSMatthew Dillon 56483f2a3aaSMatthew Dillon if ((dir = opendir(snapshots_path)) != NULL) { 56583f2a3aaSMatthew Dillon while ((den = readdir(dir)) != NULL) { 56683f2a3aaSMatthew Dillon if (den->d_name[0] == '.') 56783f2a3aaSMatthew Dillon continue; 56883f2a3aaSMatthew Dillon asprintf(&fpath, "%s/%s", snapshots_path, den->d_name); 56983f2a3aaSMatthew Dillon if (lstat(fpath, &st) == 0 && S_ISLNK(st.st_mode)) { 57083f2a3aaSMatthew Dillon migrate_one_snapshot(fd, fpath, &snapshot); 57183f2a3aaSMatthew Dillon } 57283f2a3aaSMatthew Dillon free(fpath); 57383f2a3aaSMatthew Dillon } 57483f2a3aaSMatthew Dillon closedir(dir); 57583f2a3aaSMatthew Dillon } 57683f2a3aaSMatthew Dillon migrate_one_snapshot(fd, NULL, &snapshot); 57783f2a3aaSMatthew Dillon 57883f2a3aaSMatthew Dillon } 57983f2a3aaSMatthew Dillon 58083f2a3aaSMatthew Dillon /* 58183f2a3aaSMatthew Dillon * Migrate a single snapshot. If fpath is NULL the ioctl is flushed, 58283f2a3aaSMatthew Dillon * otherwise it is flushed when it fills up. 58383f2a3aaSMatthew Dillon */ 58483f2a3aaSMatthew Dillon static void 58583f2a3aaSMatthew Dillon migrate_one_snapshot(int fd, const char *fpath, 58683f2a3aaSMatthew Dillon struct hammer_ioc_snapshot *snapshot) 58783f2a3aaSMatthew Dillon { 58883f2a3aaSMatthew Dillon if (fpath) { 58983f2a3aaSMatthew Dillon struct hammer_snapshot_data *snap; 59083f2a3aaSMatthew Dillon struct tm tm; 59183f2a3aaSMatthew Dillon time_t t; 59283f2a3aaSMatthew Dillon int year; 59383f2a3aaSMatthew Dillon int month; 59483f2a3aaSMatthew Dillon int day = 0; 59583f2a3aaSMatthew Dillon int hour = 0; 59683f2a3aaSMatthew Dillon int minute = 0; 59783f2a3aaSMatthew Dillon int r; 59883f2a3aaSMatthew Dillon char linkbuf[1024]; 59983f2a3aaSMatthew Dillon const char *ptr; 60083f2a3aaSMatthew Dillon hammer_tid_t tid; 60183f2a3aaSMatthew Dillon 60283f2a3aaSMatthew Dillon t = (time_t)-1; 60383f2a3aaSMatthew Dillon tid = (hammer_tid_t)(int64_t)-1; 60483f2a3aaSMatthew Dillon 60583f2a3aaSMatthew Dillon ptr = fpath; 60683f2a3aaSMatthew Dillon while (*ptr && *ptr != '-' && *ptr != '.') 60783f2a3aaSMatthew Dillon ++ptr; 60883f2a3aaSMatthew Dillon if (*ptr) 60983f2a3aaSMatthew Dillon ++ptr; 61083f2a3aaSMatthew Dillon r = sscanf(ptr, "%4d%2d%2d-%2d%2d", 61183f2a3aaSMatthew Dillon &year, &month, &day, &hour, &minute); 61283f2a3aaSMatthew Dillon 61383f2a3aaSMatthew Dillon if (r >= 3) { 61483f2a3aaSMatthew Dillon bzero(&tm, sizeof(tm)); 61583f2a3aaSMatthew Dillon tm.tm_isdst = -1; 61683f2a3aaSMatthew Dillon tm.tm_min = minute; 61783f2a3aaSMatthew Dillon tm.tm_hour = hour; 61883f2a3aaSMatthew Dillon tm.tm_mday = day; 61983f2a3aaSMatthew Dillon tm.tm_mon = month - 1; 62083f2a3aaSMatthew Dillon tm.tm_year = year - 1900; 62183f2a3aaSMatthew Dillon t = mktime(&tm); 62283f2a3aaSMatthew Dillon } 62383f2a3aaSMatthew Dillon bzero(linkbuf, sizeof(linkbuf)); 62483f2a3aaSMatthew Dillon if (readlink(fpath, linkbuf, sizeof(linkbuf) - 1) > 0 && 62583f2a3aaSMatthew Dillon (ptr = strrchr(linkbuf, '@')) != NULL && 62683f2a3aaSMatthew Dillon ptr > linkbuf && ptr[-1] == '@') { 62783f2a3aaSMatthew Dillon tid = strtoull(ptr + 1, NULL, 16); 62883f2a3aaSMatthew Dillon } 62983f2a3aaSMatthew Dillon if (t != (time_t)-1 && tid != (hammer_tid_t)(int64_t)-1) { 63083f2a3aaSMatthew Dillon snap = &snapshot->snaps[snapshot->count]; 63183f2a3aaSMatthew Dillon bzero(snap, sizeof(*snap)); 63283f2a3aaSMatthew Dillon snap->tid = tid; 63383f2a3aaSMatthew Dillon snap->ts = (u_int64_t)t * 1000000ULL; 63483f2a3aaSMatthew Dillon snprintf(snap->label, sizeof(snap->label), 63583f2a3aaSMatthew Dillon "migrated"); 63683f2a3aaSMatthew Dillon ++snapshot->count; 63783f2a3aaSMatthew Dillon } 63883f2a3aaSMatthew Dillon } 63983f2a3aaSMatthew Dillon 64083f2a3aaSMatthew Dillon if ((fpath == NULL && snapshot->count) || 64183f2a3aaSMatthew Dillon snapshot->count == HAMMER_SNAPS_PER_IOCTL) { 64283f2a3aaSMatthew Dillon printf(" (%d snapshots)", snapshot->count); 64383f2a3aaSMatthew Dillon again: 64483f2a3aaSMatthew Dillon if (ioctl(fd, HAMMERIOC_ADD_SNAPSHOT, snapshot) < 0) { 64583f2a3aaSMatthew Dillon printf(" Ioctl to migrate snapshots failed: %s\n", 64683f2a3aaSMatthew Dillon strerror(errno)); 64783f2a3aaSMatthew Dillon } else if (snapshot->head.error == EALREADY) { 64883f2a3aaSMatthew Dillon ++snapshot->index; 64983f2a3aaSMatthew Dillon goto again; 65083f2a3aaSMatthew Dillon } else if (snapshot->head.error) { 651*068da2c2SMatthew Dillon printf(" Ioctl to migrate snapshots failed: %s\n", 65283f2a3aaSMatthew Dillon strerror(snapshot->head.error)); 65383f2a3aaSMatthew Dillon } 65483f2a3aaSMatthew Dillon printf("index %d\n", snapshot->index); 65583f2a3aaSMatthew Dillon snapshot->index = 0; 65683f2a3aaSMatthew Dillon snapshot->count = 0; 65783f2a3aaSMatthew Dillon snapshot->head.error = 0; 65883f2a3aaSMatthew Dillon } 65983f2a3aaSMatthew Dillon } 66083f2a3aaSMatthew Dillon 6616a6e350fSMatthew Dillon static 6626a6e350fSMatthew Dillon int 6636a6e350fSMatthew Dillon strtosecs(char *ptr) 6646a6e350fSMatthew Dillon { 6656a6e350fSMatthew Dillon int val; 6666a6e350fSMatthew Dillon 6676a6e350fSMatthew Dillon val = strtol(ptr, &ptr, 0); 6686a6e350fSMatthew Dillon switch(*ptr) { 6696a6e350fSMatthew Dillon case 'd': 6706a6e350fSMatthew Dillon val *= 24; 6716a6e350fSMatthew Dillon /* fall through */ 6726a6e350fSMatthew Dillon case 'h': 6736a6e350fSMatthew Dillon val *= 60; 6746a6e350fSMatthew Dillon /* fall through */ 6756a6e350fSMatthew Dillon case 'm': 6766a6e350fSMatthew Dillon val *= 60; 6776a6e350fSMatthew Dillon /* fall through */ 6786a6e350fSMatthew Dillon case 's': 6796a6e350fSMatthew Dillon break; 6806a6e350fSMatthew Dillon default: 6816a6e350fSMatthew Dillon errx(1, "illegal suffix converting %s\n", ptr); 6826a6e350fSMatthew Dillon break; 6836a6e350fSMatthew Dillon } 6846a6e350fSMatthew Dillon return(val); 6856a6e350fSMatthew Dillon } 6866a6e350fSMatthew Dillon 6876a6e350fSMatthew Dillon static const char * 6886a6e350fSMatthew Dillon dividing_slash(const char *path) 6896a6e350fSMatthew Dillon { 6906a6e350fSMatthew Dillon int len = strlen(path); 6916a6e350fSMatthew Dillon if (len && path[len-1] == '/') 6926a6e350fSMatthew Dillon return(""); 6936a6e350fSMatthew Dillon else 6946a6e350fSMatthew Dillon return("/"); 6956a6e350fSMatthew Dillon } 6966a6e350fSMatthew Dillon 6976a6e350fSMatthew Dillon /* 6986a6e350fSMatthew Dillon * Check whether the desired period has elapsed since the last successful 6996a6e350fSMatthew Dillon * run. The run may take a while and cross a boundary so we remember the 7006a6e350fSMatthew Dillon * current time_t so we can save it later on. 7016a6e350fSMatthew Dillon * 7026a6e350fSMatthew Dillon * Periods in minutes, hours, or days are assumed to have been crossed 7036a6e350fSMatthew Dillon * if the local time crosses a minute, hour, or day boundary regardless 7046a6e350fSMatthew Dillon * of how close the last operation actually was. 7056a6e350fSMatthew Dillon */ 7066a6e350fSMatthew Dillon static int 7076a6e350fSMatthew Dillon check_period(const char *snapshots_path, const char *cmd, int arg1, 7086a6e350fSMatthew Dillon time_t *savep) 7096a6e350fSMatthew Dillon { 7106a6e350fSMatthew Dillon char *check_path; 7116a6e350fSMatthew Dillon struct tm tp1; 7126a6e350fSMatthew Dillon struct tm tp2; 7136a6e350fSMatthew Dillon FILE *fp; 7146a6e350fSMatthew Dillon time_t baset, lastt; 7156a6e350fSMatthew Dillon char buf[256]; 7166a6e350fSMatthew Dillon 7176a6e350fSMatthew Dillon time(savep); 7186a6e350fSMatthew Dillon localtime_r(savep, &tp1); 7196a6e350fSMatthew Dillon 7206a6e350fSMatthew Dillon /* 7216a6e350fSMatthew Dillon * Retrieve the start time of the last successful operation. 7226a6e350fSMatthew Dillon */ 7236a6e350fSMatthew Dillon asprintf(&check_path, "%s/.%s.period", snapshots_path, cmd); 7246a6e350fSMatthew Dillon fp = fopen(check_path, "r"); 7256a6e350fSMatthew Dillon free(check_path); 7266a6e350fSMatthew Dillon if (fp == NULL) 7276a6e350fSMatthew Dillon return(1); 7286a6e350fSMatthew Dillon if (fgets(buf, sizeof(buf), fp) == NULL) { 7296a6e350fSMatthew Dillon fclose(fp); 7306a6e350fSMatthew Dillon return(1); 7316a6e350fSMatthew Dillon } 7326a6e350fSMatthew Dillon fclose(fp); 7336a6e350fSMatthew Dillon 7346a6e350fSMatthew Dillon lastt = strtol(buf, NULL, 0); 7356a6e350fSMatthew Dillon localtime_r(&lastt, &tp2); 7366a6e350fSMatthew Dillon 7376a6e350fSMatthew Dillon /* 7386a6e350fSMatthew Dillon * Normalize the times. e.g. if asked to do something on a 1-day 7396a6e350fSMatthew Dillon * interval the operation will be performed as soon as the day 7406a6e350fSMatthew Dillon * turns over relative to the previous operation, even if the previous 7416a6e350fSMatthew Dillon * operation ran a few seconds ago just before midnight. 7426a6e350fSMatthew Dillon */ 7436a6e350fSMatthew Dillon if (arg1 % 60 == 0) { 7446a6e350fSMatthew Dillon tp1.tm_sec = 0; 7456a6e350fSMatthew Dillon tp2.tm_sec = 0; 7466a6e350fSMatthew Dillon } 7476a6e350fSMatthew Dillon if (arg1 % (60 * 60) == 0) { 7486a6e350fSMatthew Dillon tp1.tm_min = 0; 7496a6e350fSMatthew Dillon tp2.tm_min = 0; 7506a6e350fSMatthew Dillon } 7516a6e350fSMatthew Dillon if (arg1 % (24 * 60 * 60) == 0) { 7526a6e350fSMatthew Dillon tp1.tm_hour = 0; 7536a6e350fSMatthew Dillon tp2.tm_hour = 0; 7546a6e350fSMatthew Dillon } 7556a6e350fSMatthew Dillon 7566a6e350fSMatthew Dillon baset = mktime(&tp1); 7576a6e350fSMatthew Dillon lastt = mktime(&tp2); 7586a6e350fSMatthew Dillon 7596a6e350fSMatthew Dillon #if 0 7606a6e350fSMatthew Dillon printf("%lld vs %lld\n", (long long)(baset - lastt), (long long)arg1); 7616a6e350fSMatthew Dillon #endif 7626a6e350fSMatthew Dillon 7636a6e350fSMatthew Dillon if ((int)(baset - lastt) >= arg1) 7646a6e350fSMatthew Dillon return(1); 7656a6e350fSMatthew Dillon return(0); 7666a6e350fSMatthew Dillon } 7676a6e350fSMatthew Dillon 7686a6e350fSMatthew Dillon /* 7696a6e350fSMatthew Dillon * Store the start time of the last successful operation. 7706a6e350fSMatthew Dillon */ 7716a6e350fSMatthew Dillon static void 7726a6e350fSMatthew Dillon save_period(const char *snapshots_path, const char *cmd, 7736a6e350fSMatthew Dillon time_t savet) 7746a6e350fSMatthew Dillon { 7756a6e350fSMatthew Dillon char *ocheck_path; 7766a6e350fSMatthew Dillon char *ncheck_path; 7776a6e350fSMatthew Dillon FILE *fp; 7786a6e350fSMatthew Dillon 7796a6e350fSMatthew Dillon asprintf(&ocheck_path, "%s/.%s.period", snapshots_path, cmd); 7806a6e350fSMatthew Dillon asprintf(&ncheck_path, "%s/.%s.period.new", snapshots_path, cmd); 7816a6e350fSMatthew Dillon fp = fopen(ncheck_path, "w"); 7823b9fbdeaSMatthew Dillon if (fp) { 7836a6e350fSMatthew Dillon fprintf(fp, "0x%08llx\n", (long long)savet); 7846a6e350fSMatthew Dillon if (fclose(fp) == 0) 7856a6e350fSMatthew Dillon rename(ncheck_path, ocheck_path); 7866a6e350fSMatthew Dillon remove(ncheck_path); 7873b9fbdeaSMatthew Dillon } else { 7883b9fbdeaSMatthew Dillon fprintf(stderr, "hammer: Unable to create period-file %s: %s\n", 7893b9fbdeaSMatthew Dillon ncheck_path, strerror(errno)); 7903b9fbdeaSMatthew Dillon } 7916a6e350fSMatthew Dillon } 7926a6e350fSMatthew Dillon 793ff1c9800SMatthew Dillon /* 794ff1c9800SMatthew Dillon * Simply count the number of softlinks in the snapshots dir 795ff1c9800SMatthew Dillon */ 796c6c298a7SMatthew Dillon static int 79783f2a3aaSMatthew Dillon check_softlinks(int fd, int new_config, const char *snapshots_path) 798c6c298a7SMatthew Dillon { 799c6c298a7SMatthew Dillon struct dirent *den; 800c6c298a7SMatthew Dillon struct stat st; 801c6c298a7SMatthew Dillon DIR *dir; 802c6c298a7SMatthew Dillon char *fpath; 803c6c298a7SMatthew Dillon int res = 0; 804c6c298a7SMatthew Dillon 80583f2a3aaSMatthew Dillon /* 80683f2a3aaSMatthew Dillon * Old-style softlink-based snapshots 80783f2a3aaSMatthew Dillon */ 808c6c298a7SMatthew Dillon if ((dir = opendir(snapshots_path)) != NULL) { 809c6c298a7SMatthew Dillon while ((den = readdir(dir)) != NULL) { 810c6c298a7SMatthew Dillon if (den->d_name[0] == '.') 811c6c298a7SMatthew Dillon continue; 812c6c298a7SMatthew Dillon asprintf(&fpath, "%s/%s", snapshots_path, den->d_name); 813c6c298a7SMatthew Dillon if (lstat(fpath, &st) == 0 && S_ISLNK(st.st_mode)) 814c6c298a7SMatthew Dillon ++res; 815c6c298a7SMatthew Dillon free(fpath); 816c6c298a7SMatthew Dillon } 817c6c298a7SMatthew Dillon closedir(dir); 818c6c298a7SMatthew Dillon } 81983f2a3aaSMatthew Dillon 82083f2a3aaSMatthew Dillon /* 82183f2a3aaSMatthew Dillon * New-style snapshots are stored as filesystem meta-data, 82283f2a3aaSMatthew Dillon * count those too. 82383f2a3aaSMatthew Dillon */ 82483f2a3aaSMatthew Dillon if (new_config) { 82583f2a3aaSMatthew Dillon struct hammer_ioc_snapshot snapshot; 82683f2a3aaSMatthew Dillon 82783f2a3aaSMatthew Dillon bzero(&snapshot, sizeof(snapshot)); 82883f2a3aaSMatthew Dillon do { 82983f2a3aaSMatthew Dillon if (ioctl(fd, HAMMERIOC_GET_SNAPSHOT, &snapshot) < 0) { 83083f2a3aaSMatthew Dillon err(2, "hammer cleanup: check_softlink " 83183f2a3aaSMatthew Dillon "snapshot error"); 83283f2a3aaSMatthew Dillon /* not reached */ 83383f2a3aaSMatthew Dillon } 83483f2a3aaSMatthew Dillon res += snapshot.count; 83583f2a3aaSMatthew Dillon } while (snapshot.head.error == 0 && snapshot.count); 83683f2a3aaSMatthew Dillon } 837c6c298a7SMatthew Dillon return (res); 838c6c298a7SMatthew Dillon } 839c6c298a7SMatthew Dillon 8406a6e350fSMatthew Dillon /* 841ff1c9800SMatthew Dillon * Clean up expired softlinks in the snapshots dir 842ff1c9800SMatthew Dillon */ 843ff1c9800SMatthew Dillon static void 84483f2a3aaSMatthew Dillon cleanup_softlinks(int fd, int new_config, 84583f2a3aaSMatthew Dillon const char *snapshots_path, int arg2, char *arg3) 846ff1c9800SMatthew Dillon { 847ff1c9800SMatthew Dillon struct dirent *den; 848ff1c9800SMatthew Dillon struct stat st; 849ff1c9800SMatthew Dillon DIR *dir; 850ff1c9800SMatthew Dillon char *fpath; 8515e435c92SMatthew Dillon int anylink = 0; 8525e435c92SMatthew Dillon 85309e1b0d6SMatthew Dillon if (arg3 != NULL && strstr(arg3, "any") != NULL) 8545e435c92SMatthew Dillon anylink = 1; 855ff1c9800SMatthew Dillon 856ff1c9800SMatthew Dillon if ((dir = opendir(snapshots_path)) != NULL) { 857ff1c9800SMatthew Dillon while ((den = readdir(dir)) != NULL) { 858ff1c9800SMatthew Dillon if (den->d_name[0] == '.') 859ff1c9800SMatthew Dillon continue; 860ff1c9800SMatthew Dillon asprintf(&fpath, "%s/%s", snapshots_path, den->d_name); 861ff1c9800SMatthew Dillon if (lstat(fpath, &st) == 0 && S_ISLNK(st.st_mode) && 8625e435c92SMatthew Dillon (anylink || strncmp(den->d_name, "snap-", 5) == 0) 8635e435c92SMatthew Dillon ) { 864ff1c9800SMatthew Dillon if (check_expired(den->d_name, arg2)) { 865ff1c9800SMatthew Dillon if (VerboseOpt) { 866ff1c9800SMatthew Dillon printf(" expire %s\n", 867ff1c9800SMatthew Dillon fpath); 868ff1c9800SMatthew Dillon } 869ff1c9800SMatthew Dillon remove(fpath); 870ff1c9800SMatthew Dillon } 871ff1c9800SMatthew Dillon } 872ff1c9800SMatthew Dillon free(fpath); 873ff1c9800SMatthew Dillon } 874ff1c9800SMatthew Dillon closedir(dir); 875ff1c9800SMatthew Dillon } 87683f2a3aaSMatthew Dillon 87783f2a3aaSMatthew Dillon /* 87883f2a3aaSMatthew Dillon * New-style snapshots are stored as filesystem meta-data, 87983f2a3aaSMatthew Dillon * count those too. 88083f2a3aaSMatthew Dillon */ 88183f2a3aaSMatthew Dillon if (new_config) { 88283f2a3aaSMatthew Dillon struct hammer_ioc_snapshot snapshot; 88383f2a3aaSMatthew Dillon struct hammer_ioc_snapshot dsnapshot; 88483f2a3aaSMatthew Dillon struct hammer_snapshot_data *snap; 88583f2a3aaSMatthew Dillon struct tm *tp; 88683f2a3aaSMatthew Dillon time_t t; 88783f2a3aaSMatthew Dillon char snapts[32]; 88883f2a3aaSMatthew Dillon u_int32_t i; 88983f2a3aaSMatthew Dillon 89083f2a3aaSMatthew Dillon bzero(&snapshot, sizeof(snapshot)); 89183f2a3aaSMatthew Dillon bzero(&dsnapshot, sizeof(dsnapshot)); 89283f2a3aaSMatthew Dillon do { 89383f2a3aaSMatthew Dillon if (ioctl(fd, HAMMERIOC_GET_SNAPSHOT, &snapshot) < 0) { 89483f2a3aaSMatthew Dillon err(2, "hammer cleanup: check_softlink " 89583f2a3aaSMatthew Dillon "snapshot error"); 89683f2a3aaSMatthew Dillon /* not reached */ 89783f2a3aaSMatthew Dillon } 89883f2a3aaSMatthew Dillon for (i = 0; i < snapshot.count; ++i) { 89983f2a3aaSMatthew Dillon snap = &snapshot.snaps[i]; 90083f2a3aaSMatthew Dillon t = time(NULL) - snap->ts / 1000000ULL; 901*068da2c2SMatthew Dillon if ((int)t > arg2 && snap->tid != 0) { 90283f2a3aaSMatthew Dillon dsnapshot.snaps[dsnapshot.count++] = 90383f2a3aaSMatthew Dillon *snap; 90483f2a3aaSMatthew Dillon } 90583f2a3aaSMatthew Dillon if ((int)t > arg2 && VerboseOpt) { 90683f2a3aaSMatthew Dillon tp = localtime(&t); 90783f2a3aaSMatthew Dillon strftime(snapts, sizeof(snapts), 90883f2a3aaSMatthew Dillon "%Y-%m-%d %H:%M:%S %Z", tp); 90983f2a3aaSMatthew Dillon printf(" expire 0x%016jx %s %s\n", 91083f2a3aaSMatthew Dillon (uintmax_t)snap->tid, 91183f2a3aaSMatthew Dillon snapts, 91283f2a3aaSMatthew Dillon snap->label); 91383f2a3aaSMatthew Dillon } 91483f2a3aaSMatthew Dillon if (dsnapshot.count == HAMMER_SNAPS_PER_IOCTL) { 91583f2a3aaSMatthew Dillon if (ioctl(fd, HAMMERIOC_DEL_SNAPSHOT, &dsnapshot) < 0) { 916*068da2c2SMatthew Dillon printf(" Ioctl to delete snapshots failed: %s index %d\n", strerror(errno), dsnapshot.index); 91783f2a3aaSMatthew Dillon } else if (dsnapshot.head.error) { 91883f2a3aaSMatthew Dillon printf(" Ioctl to delete snapshots failed: %s\n", strerror(dsnapshot.head.error)); 919*068da2c2SMatthew Dillon exit(1); 92083f2a3aaSMatthew Dillon } 921*068da2c2SMatthew Dillon dsnapshot.index = 0; 92283f2a3aaSMatthew Dillon dsnapshot.count = 0; 92383f2a3aaSMatthew Dillon dsnapshot.head.error = 0; 92483f2a3aaSMatthew Dillon } 92583f2a3aaSMatthew Dillon } 92683f2a3aaSMatthew Dillon } while (snapshot.head.error == 0 && snapshot.count); 92783f2a3aaSMatthew Dillon 92883f2a3aaSMatthew Dillon if (dsnapshot.count) { 92983f2a3aaSMatthew Dillon if (ioctl(fd, HAMMERIOC_DEL_SNAPSHOT, &dsnapshot) < 0) { 93083f2a3aaSMatthew Dillon printf(" Ioctl to delete snapshots failed: %s\n", strerror(errno)); 93183f2a3aaSMatthew Dillon } else if (dsnapshot.head.error) { 93283f2a3aaSMatthew Dillon printf(" Ioctl to delete snapshots failed: %s\n", strerror(dsnapshot.head.error)); 93383f2a3aaSMatthew Dillon } 93483f2a3aaSMatthew Dillon dsnapshot.count = 0; 935*068da2c2SMatthew Dillon dsnapshot.index = 0; 93683f2a3aaSMatthew Dillon dsnapshot.head.error = 0; 93783f2a3aaSMatthew Dillon } 93883f2a3aaSMatthew Dillon } 939ff1c9800SMatthew Dillon } 940ff1c9800SMatthew Dillon 941ff1c9800SMatthew Dillon /* 942ff1c9800SMatthew Dillon * Take a softlink path in the form snap-yyyymmdd-hhmm and the 943ff1c9800SMatthew Dillon * expiration in seconds (arg2) and return non-zero if the softlink 944ff1c9800SMatthew Dillon * has expired. 945ff1c9800SMatthew Dillon */ 946ff1c9800SMatthew Dillon static int 947ff1c9800SMatthew Dillon check_expired(const char *fpath, int arg2) 948ff1c9800SMatthew Dillon { 949ff1c9800SMatthew Dillon struct tm tm; 950ff1c9800SMatthew Dillon time_t t; 951ff1c9800SMatthew Dillon int year; 952ff1c9800SMatthew Dillon int month; 9535e435c92SMatthew Dillon int day = 0; 9545e435c92SMatthew Dillon int hour = 0; 9555e435c92SMatthew Dillon int minute = 0; 956ff1c9800SMatthew Dillon int r; 957ff1c9800SMatthew Dillon 9585e435c92SMatthew Dillon while (*fpath && *fpath != '-' && *fpath != '.') 9595e435c92SMatthew Dillon ++fpath; 9605e435c92SMatthew Dillon if (*fpath) 9615e435c92SMatthew Dillon ++fpath; 9625e435c92SMatthew Dillon 9635e435c92SMatthew Dillon r = sscanf(fpath, "%4d%2d%2d-%2d%2d", 964ff1c9800SMatthew Dillon &year, &month, &day, &hour, &minute); 9655e435c92SMatthew Dillon 9665e435c92SMatthew Dillon if (r >= 3) { 967ff1c9800SMatthew Dillon bzero(&tm, sizeof(tm)); 968ff1c9800SMatthew Dillon tm.tm_isdst = -1; 969ff1c9800SMatthew Dillon tm.tm_min = minute; 970ff1c9800SMatthew Dillon tm.tm_hour = hour; 971ff1c9800SMatthew Dillon tm.tm_mday = day; 972ff1c9800SMatthew Dillon tm.tm_mon = month - 1; 973ff1c9800SMatthew Dillon tm.tm_year = year - 1900; 9745e435c92SMatthew Dillon t = mktime(&tm); 9755e435c92SMatthew Dillon if (t == (time_t)-1) 9765e435c92SMatthew Dillon return(0); 9775e435c92SMatthew Dillon t = time(NULL) - t; 978ff1c9800SMatthew Dillon if ((int)t > arg2) 979ff1c9800SMatthew Dillon return(1); 980ff1c9800SMatthew Dillon } 981ff1c9800SMatthew Dillon return(0); 982ff1c9800SMatthew Dillon } 983ff1c9800SMatthew Dillon 984ff1c9800SMatthew Dillon /* 9856a6e350fSMatthew Dillon * Issue a snapshot. 9866a6e350fSMatthew Dillon */ 9876a6e350fSMatthew Dillon static int 988b5ec5ad4SMatthew Dillon create_snapshot(const char *path, const char *snapshots_path) 9896a6e350fSMatthew Dillon { 9906a6e350fSMatthew Dillon int r; 9916a6e350fSMatthew Dillon 992ff1c9800SMatthew Dillon runcmd(&r, "hammer snapshot %s %s", path, snapshots_path); 9936a6e350fSMatthew Dillon return(r); 9946a6e350fSMatthew Dillon } 9956a6e350fSMatthew Dillon 9966a6e350fSMatthew Dillon static int 9976a6e350fSMatthew Dillon cleanup_prune(const char *path __unused, const char *snapshots_path, 998c6c298a7SMatthew Dillon int arg1 __unused, int arg2, int snapshots_disabled) 9996a6e350fSMatthew Dillon { 1000c6c298a7SMatthew Dillon /* 1001c6c298a7SMatthew Dillon * If snapshots have been disabled run prune-everything instead 1002c6c298a7SMatthew Dillon * of prune. 1003c6c298a7SMatthew Dillon */ 1004c6c298a7SMatthew Dillon if (snapshots_disabled && arg2) { 1005c6c298a7SMatthew Dillon runcmd(NULL, "hammer -c %s/.prune.cycle -t %d prune-everything %s", 1006c6c298a7SMatthew Dillon snapshots_path, arg2, path); 1007c6c298a7SMatthew Dillon } else if (snapshots_disabled) { 1008c6c298a7SMatthew Dillon runcmd(NULL, "hammer prune-everything %s", path); 1009c6c298a7SMatthew Dillon } else if (arg2) { 10106a6e350fSMatthew Dillon runcmd(NULL, "hammer -c %s/.prune.cycle -t %d prune %s", 10116a6e350fSMatthew Dillon snapshots_path, arg2, snapshots_path); 10126a6e350fSMatthew Dillon } else { 10136a6e350fSMatthew Dillon runcmd(NULL, "hammer prune %s", snapshots_path); 10146a6e350fSMatthew Dillon } 10156a6e350fSMatthew Dillon return(0); 10166a6e350fSMatthew Dillon } 10176a6e350fSMatthew Dillon 10186a6e350fSMatthew Dillon static int 10190b8bd7daSMatthew Dillon cleanup_rebalance(const char *path, const char *snapshots_path, 10200b8bd7daSMatthew Dillon int arg1 __unused, int arg2) 10210b8bd7daSMatthew Dillon { 10220b8bd7daSMatthew Dillon if (VerboseOpt == 0) { 10230b8bd7daSMatthew Dillon printf("."); 10240b8bd7daSMatthew Dillon fflush(stdout); 10250b8bd7daSMatthew Dillon } 10260b8bd7daSMatthew Dillon 10270b8bd7daSMatthew Dillon runcmd(NULL, 10280b8bd7daSMatthew Dillon "hammer -c %s/.rebalance.cycle -t %d rebalance %s", 10290b8bd7daSMatthew Dillon snapshots_path, arg2, path); 10300b8bd7daSMatthew Dillon if (VerboseOpt == 0) { 10310b8bd7daSMatthew Dillon printf("."); 10320b8bd7daSMatthew Dillon fflush(stdout); 10330b8bd7daSMatthew Dillon } 10340b8bd7daSMatthew Dillon if (VerboseOpt == 0) 10350b8bd7daSMatthew Dillon printf("\n"); 10360b8bd7daSMatthew Dillon return(0); 10370b8bd7daSMatthew Dillon } 10380b8bd7daSMatthew Dillon 10390b8bd7daSMatthew Dillon static int 10406a6e350fSMatthew Dillon cleanup_reblock(const char *path, const char *snapshots_path, 10416a6e350fSMatthew Dillon int arg1 __unused, int arg2) 10426a6e350fSMatthew Dillon { 10436a6e350fSMatthew Dillon if (VerboseOpt == 0) { 10446a6e350fSMatthew Dillon printf("."); 10456a6e350fSMatthew Dillon fflush(stdout); 10466a6e350fSMatthew Dillon } 1047797a0b63SMatthew Dillon 1048797a0b63SMatthew Dillon /* 1049797a0b63SMatthew Dillon * When reblocking the B-Tree always reblock everything in normal 1050797a0b63SMatthew Dillon * mode. 1051797a0b63SMatthew Dillon */ 10526a6e350fSMatthew Dillon runcmd(NULL, 1053797a0b63SMatthew Dillon "hammer -c %s/.reblock-1.cycle -t %d reblock-btree %s", 10546a6e350fSMatthew Dillon snapshots_path, arg2, path); 10556a6e350fSMatthew Dillon if (VerboseOpt == 0) { 10566a6e350fSMatthew Dillon printf("."); 10576a6e350fSMatthew Dillon fflush(stdout); 10586a6e350fSMatthew Dillon } 1059797a0b63SMatthew Dillon 1060797a0b63SMatthew Dillon /* 1061797a0b63SMatthew Dillon * When reblocking the inodes always reblock everything in normal 1062797a0b63SMatthew Dillon * mode. 1063797a0b63SMatthew Dillon */ 10646a6e350fSMatthew Dillon runcmd(NULL, 1065797a0b63SMatthew Dillon "hammer -c %s/.reblock-2.cycle -t %d reblock-inodes %s", 10666a6e350fSMatthew Dillon snapshots_path, arg2, path); 10676a6e350fSMatthew Dillon if (VerboseOpt == 0) { 10686a6e350fSMatthew Dillon printf("."); 10696a6e350fSMatthew Dillon fflush(stdout); 10706a6e350fSMatthew Dillon } 1071797a0b63SMatthew Dillon 1072797a0b63SMatthew Dillon /* 1073797a0b63SMatthew Dillon * When reblocking the directories always reblock everything in normal 1074797a0b63SMatthew Dillon * mode. 1075797a0b63SMatthew Dillon */ 1076797a0b63SMatthew Dillon runcmd(NULL, 1077797a0b63SMatthew Dillon "hammer -c %s/.reblock-4.cycle -t %d reblock-dirs %s", 1078797a0b63SMatthew Dillon snapshots_path, arg2, path); 1079797a0b63SMatthew Dillon if (VerboseOpt == 0) { 1080797a0b63SMatthew Dillon printf("."); 1081797a0b63SMatthew Dillon fflush(stdout); 1082797a0b63SMatthew Dillon } 1083797a0b63SMatthew Dillon 1084797a0b63SMatthew Dillon /* 1085797a0b63SMatthew Dillon * Do not reblock all the data in normal mode. 1086797a0b63SMatthew Dillon */ 10876a6e350fSMatthew Dillon runcmd(NULL, 10886a6e350fSMatthew Dillon "hammer -c %s/.reblock-3.cycle -t %d reblock-data %s 95", 10896a6e350fSMatthew Dillon snapshots_path, arg2, path); 10906a6e350fSMatthew Dillon if (VerboseOpt == 0) 10916a6e350fSMatthew Dillon printf("\n"); 10926a6e350fSMatthew Dillon return(0); 10936a6e350fSMatthew Dillon } 10946a6e350fSMatthew Dillon 10956a6e350fSMatthew Dillon static int 10966a6e350fSMatthew Dillon cleanup_recopy(const char *path, const char *snapshots_path, 10976a6e350fSMatthew Dillon int arg1 __unused, int arg2) 10986a6e350fSMatthew Dillon { 10996a6e350fSMatthew Dillon if (VerboseOpt == 0) { 11006a6e350fSMatthew Dillon printf("."); 11016a6e350fSMatthew Dillon fflush(stdout); 11026a6e350fSMatthew Dillon } 11036a6e350fSMatthew Dillon runcmd(NULL, 11046a6e350fSMatthew Dillon "hammer -c %s/.recopy-1.cycle -t %d reblock-btree %s", 11056a6e350fSMatthew Dillon snapshots_path, arg2, path); 11066a6e350fSMatthew Dillon if (VerboseOpt == 0) { 11076a6e350fSMatthew Dillon printf("."); 11086a6e350fSMatthew Dillon fflush(stdout); 11096a6e350fSMatthew Dillon } 11106a6e350fSMatthew Dillon runcmd(NULL, 11116a6e350fSMatthew Dillon "hammer -c %s/.recopy-2.cycle -t %d reblock-inodes %s", 11126a6e350fSMatthew Dillon snapshots_path, arg2, path); 11136a6e350fSMatthew Dillon if (VerboseOpt == 0) { 11146a6e350fSMatthew Dillon printf("."); 11156a6e350fSMatthew Dillon fflush(stdout); 11166a6e350fSMatthew Dillon } 11176a6e350fSMatthew Dillon runcmd(NULL, 1118797a0b63SMatthew Dillon "hammer -c %s/.recopy-4.cycle -t %d reblock-dirs %s", 1119797a0b63SMatthew Dillon snapshots_path, arg2, path); 1120797a0b63SMatthew Dillon if (VerboseOpt == 0) { 1121797a0b63SMatthew Dillon printf("."); 1122797a0b63SMatthew Dillon fflush(stdout); 1123797a0b63SMatthew Dillon } 1124797a0b63SMatthew Dillon runcmd(NULL, 11256a6e350fSMatthew Dillon "hammer -c %s/.recopy-3.cycle -t %d reblock-data %s", 11266a6e350fSMatthew Dillon snapshots_path, arg2, path); 11276a6e350fSMatthew Dillon if (VerboseOpt == 0) 11286a6e350fSMatthew Dillon printf("\n"); 11296a6e350fSMatthew Dillon return(0); 11306a6e350fSMatthew Dillon } 11316a6e350fSMatthew Dillon 11326a6e350fSMatthew Dillon static 11336a6e350fSMatthew Dillon void 11346a6e350fSMatthew Dillon runcmd(int *resp, const char *ctl, ...) 11356a6e350fSMatthew Dillon { 11366a6e350fSMatthew Dillon va_list va; 11376a6e350fSMatthew Dillon char *cmd; 11386a6e350fSMatthew Dillon char *arg; 11396a6e350fSMatthew Dillon char **av; 11406a6e350fSMatthew Dillon int n; 11416a6e350fSMatthew Dillon int nmax; 11426a6e350fSMatthew Dillon int res; 11436a6e350fSMatthew Dillon pid_t pid; 11446a6e350fSMatthew Dillon 11456a6e350fSMatthew Dillon /* 11466a6e350fSMatthew Dillon * Generate the command 11476a6e350fSMatthew Dillon */ 11486a6e350fSMatthew Dillon va_start(va, ctl); 11496a6e350fSMatthew Dillon vasprintf(&cmd, ctl, va); 11506a6e350fSMatthew Dillon va_end(va); 11516a6e350fSMatthew Dillon if (VerboseOpt) 11526a6e350fSMatthew Dillon printf(" %s\n", cmd); 11536a6e350fSMatthew Dillon 11546a6e350fSMatthew Dillon /* 11556a6e350fSMatthew Dillon * Break us down into arguments. We do not just use system() here 11566a6e350fSMatthew Dillon * because it blocks SIGINT and friends. 11576a6e350fSMatthew Dillon */ 11586a6e350fSMatthew Dillon n = 0; 11596a6e350fSMatthew Dillon nmax = 16; 11606a6e350fSMatthew Dillon av = malloc(sizeof(char *) * nmax); 11616a6e350fSMatthew Dillon 11626a6e350fSMatthew Dillon for (arg = strtok(cmd, WS); arg; arg = strtok(NULL, WS)) { 1163c453712aSMatthew Dillon if (n == nmax - 1) { 11646a6e350fSMatthew Dillon nmax += 16; 11656a6e350fSMatthew Dillon av = realloc(av, sizeof(char *) * nmax); 11666a6e350fSMatthew Dillon } 11676a6e350fSMatthew Dillon av[n++] = arg; 11686a6e350fSMatthew Dillon } 1169c453712aSMatthew Dillon av[n++] = NULL; 11706a6e350fSMatthew Dillon 11716a6e350fSMatthew Dillon /* 11726a6e350fSMatthew Dillon * Run the command. 11736a6e350fSMatthew Dillon */ 1174445faa69SMatthew Dillon RunningIoctl = 1; 11756a6e350fSMatthew Dillon if ((pid = fork()) == 0) { 11766a6e350fSMatthew Dillon if (VerboseOpt < 2) { 11776a6e350fSMatthew Dillon int fd = open("/dev/null", O_RDWR); 11786a6e350fSMatthew Dillon dup2(fd, 1); 11796a6e350fSMatthew Dillon close(fd); 11806a6e350fSMatthew Dillon } 11816a6e350fSMatthew Dillon execvp(av[0], av); 11826a6e350fSMatthew Dillon _exit(127); 11836a6e350fSMatthew Dillon } else if (pid < 0) { 11846a6e350fSMatthew Dillon res = 127; 11856a6e350fSMatthew Dillon } else { 11866a6e350fSMatthew Dillon int status; 1187445faa69SMatthew Dillon 11886a6e350fSMatthew Dillon while (waitpid(pid, &status, 0) != pid) 11896a6e350fSMatthew Dillon ; 11906a6e350fSMatthew Dillon res = WEXITSTATUS(status); 11916a6e350fSMatthew Dillon } 1192445faa69SMatthew Dillon RunningIoctl = 0; 1193445faa69SMatthew Dillon if (DidInterrupt) 1194445faa69SMatthew Dillon _exit(1); 11956a6e350fSMatthew Dillon 11966a6e350fSMatthew Dillon free(cmd); 11976a6e350fSMatthew Dillon free(av); 11986a6e350fSMatthew Dillon if (resp) 11996a6e350fSMatthew Dillon *resp = res; 12006a6e350fSMatthew Dillon } 1201