12654012fSReza Sabdar /* 28c4f9701SJanice Chang * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. 3*40a5c998SMatthew Ahrens * Copyright (c) 2013, 2015 by Delphix. All rights reserved. 4a7a845e4SSteven Hartland * Copyright (c) 2013 Steven Hartland. All rights reserved. 52654012fSReza Sabdar */ 62654012fSReza Sabdar 72654012fSReza Sabdar /* 82654012fSReza Sabdar * BSD 3 Clause License 92654012fSReza Sabdar * 102654012fSReza Sabdar * Copyright (c) 2007, The Storage Networking Industry Association. 112654012fSReza Sabdar * 122654012fSReza Sabdar * Redistribution and use in source and binary forms, with or without 132654012fSReza Sabdar * modification, are permitted provided that the following conditions 142654012fSReza Sabdar * are met: 152654012fSReza Sabdar * - Redistributions of source code must retain the above copyright 162654012fSReza Sabdar * notice, this list of conditions and the following disclaimer. 172654012fSReza Sabdar * 182654012fSReza Sabdar * - Redistributions in binary form must reproduce the above copyright 192654012fSReza Sabdar * notice, this list of conditions and the following disclaimer in 202654012fSReza Sabdar * the documentation and/or other materials provided with the 212654012fSReza Sabdar * distribution. 222654012fSReza Sabdar * 232654012fSReza Sabdar * - Neither the name of The Storage Networking Industry Association (SNIA) 242654012fSReza Sabdar * nor the names of its contributors may be used to endorse or promote 252654012fSReza Sabdar * products derived from this software without specific prior written 262654012fSReza Sabdar * permission. 272654012fSReza Sabdar * 282654012fSReza Sabdar * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 292654012fSReza Sabdar * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 302654012fSReza Sabdar * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 312654012fSReza Sabdar * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 322654012fSReza Sabdar * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 332654012fSReza Sabdar * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 342654012fSReza Sabdar * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 352654012fSReza Sabdar * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 362654012fSReza Sabdar * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 372654012fSReza Sabdar * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 382654012fSReza Sabdar * POSSIBILITY OF SUCH DAMAGE. 392654012fSReza Sabdar */ 402654012fSReza Sabdar 412654012fSReza Sabdar #include <stdio.h> 422654012fSReza Sabdar #include <string.h> 432654012fSReza Sabdar #include "ndmpd.h" 442654012fSReza Sabdar #include <libzfs.h> 452654012fSReza Sabdar 46876b86efSReza Sabdar typedef struct snap_param { 47876b86efSReza Sabdar char *snp_name; 48876b86efSReza Sabdar boolean_t snp_found; 49876b86efSReza Sabdar } snap_param_t; 502654012fSReza Sabdar 51876b86efSReza Sabdar static int cleanup_fd = -1; 522654012fSReza Sabdar 532654012fSReza Sabdar /* 542654012fSReza Sabdar * ndmp_has_backup 552654012fSReza Sabdar * 562654012fSReza Sabdar * Call backup function which looks for backup snapshot. 572654012fSReza Sabdar * This is a callback function used with zfs_iter_snapshots. 582654012fSReza Sabdar * 592654012fSReza Sabdar * Parameters: 602654012fSReza Sabdar * zhp (input) - ZFS handle pointer 612654012fSReza Sabdar * data (output) - 0 - no backup snapshot 622654012fSReza Sabdar * 1 - has backup snapshot 632654012fSReza Sabdar * 642654012fSReza Sabdar * Returns: 652654012fSReza Sabdar * 0: on success 662654012fSReza Sabdar * -1: otherwise 672654012fSReza Sabdar */ 682654012fSReza Sabdar static int 692654012fSReza Sabdar ndmp_has_backup(zfs_handle_t *zhp, void *data) 702654012fSReza Sabdar { 712654012fSReza Sabdar const char *name; 72876b86efSReza Sabdar snap_param_t *chp = (snap_param_t *)data; 732654012fSReza Sabdar 742654012fSReza Sabdar name = zfs_get_name(zhp); 752654012fSReza Sabdar if (name == NULL || 76876b86efSReza Sabdar strstr(name, chp->snp_name) == NULL) { 772654012fSReza Sabdar zfs_close(zhp); 782654012fSReza Sabdar return (-1); 792654012fSReza Sabdar } 802654012fSReza Sabdar 81876b86efSReza Sabdar chp->snp_found = 1; 822654012fSReza Sabdar zfs_close(zhp); 832654012fSReza Sabdar 842654012fSReza Sabdar return (0); 852654012fSReza Sabdar } 862654012fSReza Sabdar 872654012fSReza Sabdar /* 88876b86efSReza Sabdar * ndmp_has_backup_snapshot 892654012fSReza Sabdar * 902654012fSReza Sabdar * Returns TRUE if the volume has an active backup snapshot, otherwise, 912654012fSReza Sabdar * returns FALSE. 922654012fSReza Sabdar * 932654012fSReza Sabdar * Parameters: 942654012fSReza Sabdar * volname (input) - name of the volume 952654012fSReza Sabdar * 962654012fSReza Sabdar * Returns: 972654012fSReza Sabdar * 0: on success 982654012fSReza Sabdar * -1: otherwise 992654012fSReza Sabdar */ 1002654012fSReza Sabdar static int 101876b86efSReza Sabdar ndmp_has_backup_snapshot(char *volname, char *jobname) 1022654012fSReza Sabdar { 1032654012fSReza Sabdar zfs_handle_t *zhp; 104876b86efSReza Sabdar snap_param_t snp; 105*40a5c998SMatthew Ahrens char chname[ZFS_MAX_DATASET_NAME_LEN]; 1062654012fSReza Sabdar 1072654012fSReza Sabdar (void) mutex_lock(&zlib_mtx); 1082654012fSReza Sabdar if ((zhp = zfs_open(zlibh, volname, ZFS_TYPE_DATASET)) == 0) { 109876b86efSReza Sabdar NDMP_LOG(LOG_ERR, "Cannot open snapshot %s.", volname); 1102654012fSReza Sabdar (void) mutex_unlock(&zlib_mtx); 1112654012fSReza Sabdar return (-1); 1122654012fSReza Sabdar } 1132654012fSReza Sabdar 114876b86efSReza Sabdar snp.snp_found = 0; 115*40a5c998SMatthew Ahrens (void) snprintf(chname, ZFS_MAX_DATASET_NAME_LEN, "@%s", jobname); 116876b86efSReza Sabdar snp.snp_name = chname; 1172654012fSReza Sabdar 118876b86efSReza Sabdar (void) zfs_iter_snapshots(zhp, ndmp_has_backup, &snp); 1192654012fSReza Sabdar zfs_close(zhp); 1202654012fSReza Sabdar (void) mutex_unlock(&zlib_mtx); 1212654012fSReza Sabdar 122876b86efSReza Sabdar return (snp.snp_found); 1232654012fSReza Sabdar } 1242654012fSReza Sabdar 1252654012fSReza Sabdar /* 126876b86efSReza Sabdar * ndmp_create_snapshot 1272654012fSReza Sabdar * 128876b86efSReza Sabdar * This function will parse the path to get the real volume name. 129876b86efSReza Sabdar * It will then create a snapshot based on volume and job name. 1302654012fSReza Sabdar * This function should be called before the NDMP backup is started. 1312654012fSReza Sabdar * 1322654012fSReza Sabdar * Parameters: 1332654012fSReza Sabdar * vol_name (input) - name of the volume 1342654012fSReza Sabdar * 1352654012fSReza Sabdar * Returns: 1362654012fSReza Sabdar * 0: on success 1372654012fSReza Sabdar * -1: otherwise 1382654012fSReza Sabdar */ 1392654012fSReza Sabdar int 140876b86efSReza Sabdar ndmp_create_snapshot(char *vol_name, char *jname) 1412654012fSReza Sabdar { 142*40a5c998SMatthew Ahrens char vol[ZFS_MAX_DATASET_NAME_LEN]; 1432654012fSReza Sabdar 1442654012fSReza Sabdar if (vol_name == 0 || 1452654012fSReza Sabdar get_zfsvolname(vol, sizeof (vol), vol_name) == -1) 1462654012fSReza Sabdar return (0); 1472654012fSReza Sabdar 1482654012fSReza Sabdar /* 149876b86efSReza Sabdar * If there is an old snapshot left from the previous 150876b86efSReza Sabdar * backup it could be stale one and it must be 1512654012fSReza Sabdar * removed before using it. 1522654012fSReza Sabdar */ 153876b86efSReza Sabdar if (ndmp_has_backup_snapshot(vol, jname)) 154876b86efSReza Sabdar (void) snapshot_destroy(vol, jname, B_FALSE, B_TRUE, NULL); 1552654012fSReza Sabdar 156876b86efSReza Sabdar return (snapshot_create(vol, jname, B_FALSE, B_TRUE)); 1572654012fSReza Sabdar } 1582654012fSReza Sabdar 1592654012fSReza Sabdar /* 160876b86efSReza Sabdar * ndmp_remove_snapshot 1612654012fSReza Sabdar * 162876b86efSReza Sabdar * This function will parse the path to get the real volume name. 163876b86efSReza Sabdar * It will then remove the snapshot for that volume and job name. 1642654012fSReza Sabdar * This function should be called after NDMP backup is finished. 1652654012fSReza Sabdar * 1662654012fSReza Sabdar * Parameters: 1672654012fSReza Sabdar * vol_name (input) - name of the volume 1682654012fSReza Sabdar * 1692654012fSReza Sabdar * Returns: 1702654012fSReza Sabdar * 0: on success 1712654012fSReza Sabdar * -1: otherwise 1722654012fSReza Sabdar */ 1732654012fSReza Sabdar int 174876b86efSReza Sabdar ndmp_remove_snapshot(char *vol_name, char *jname) 1752654012fSReza Sabdar { 176*40a5c998SMatthew Ahrens char vol[ZFS_MAX_DATASET_NAME_LEN]; 1772654012fSReza Sabdar 1782654012fSReza Sabdar if (vol_name == 0 || 179876b86efSReza Sabdar get_zfsvolname(vol, sizeof (vol), vol_name) == -1) 1802654012fSReza Sabdar return (0); 1812654012fSReza Sabdar 182876b86efSReza Sabdar return (snapshot_destroy(vol, jname, B_FALSE, B_TRUE, NULL)); 183876b86efSReza Sabdar } 1842654012fSReza Sabdar 185876b86efSReza Sabdar /* 186876b86efSReza Sabdar * Put a hold on snapshot 187876b86efSReza Sabdar */ 188876b86efSReza Sabdar int 189876b86efSReza Sabdar snapshot_hold(char *volname, char *snapname, char *jname, boolean_t recursive) 190876b86efSReza Sabdar { 191876b86efSReza Sabdar zfs_handle_t *zhp; 192876b86efSReza Sabdar char *p; 193876b86efSReza Sabdar 194876b86efSReza Sabdar if ((zhp = zfs_open(zlibh, volname, ZFS_TYPE_DATASET)) == 0) { 195876b86efSReza Sabdar NDMP_LOG(LOG_ERR, "Cannot open volume %s.", volname); 196876b86efSReza Sabdar return (-1); 197876b86efSReza Sabdar } 198876b86efSReza Sabdar 199876b86efSReza Sabdar if (cleanup_fd == -1 && (cleanup_fd = open(ZFS_DEV, 200876b86efSReza Sabdar O_RDWR|O_EXCL)) < 0) { 201876b86efSReza Sabdar NDMP_LOG(LOG_ERR, "Cannot open dev %d", errno); 202876b86efSReza Sabdar zfs_close(zhp); 203876b86efSReza Sabdar return (-1); 204876b86efSReza Sabdar } 205876b86efSReza Sabdar 206876b86efSReza Sabdar p = strchr(snapname, '@') + 1; 207a7a845e4SSteven Hartland if (zfs_hold(zhp, p, jname, recursive, cleanup_fd) != 0) { 208876b86efSReza Sabdar NDMP_LOG(LOG_ERR, "Cannot hold snapshot %s", p); 209876b86efSReza Sabdar zfs_close(zhp); 210876b86efSReza Sabdar return (-1); 211876b86efSReza Sabdar } 212876b86efSReza Sabdar zfs_close(zhp); 213876b86efSReza Sabdar return (0); 214876b86efSReza Sabdar } 215876b86efSReza Sabdar 216876b86efSReza Sabdar int 217876b86efSReza Sabdar snapshot_release(char *volname, char *snapname, char *jname, 218876b86efSReza Sabdar boolean_t recursive) 219876b86efSReza Sabdar { 220876b86efSReza Sabdar zfs_handle_t *zhp; 221876b86efSReza Sabdar char *p; 222876b86efSReza Sabdar int rv = 0; 223876b86efSReza Sabdar 224876b86efSReza Sabdar if ((zhp = zfs_open(zlibh, volname, ZFS_TYPE_DATASET)) == 0) { 225876b86efSReza Sabdar NDMP_LOG(LOG_ERR, "Cannot open volume %s", volname); 226876b86efSReza Sabdar return (-1); 227876b86efSReza Sabdar } 228876b86efSReza Sabdar 229876b86efSReza Sabdar p = strchr(snapname, '@') + 1; 230876b86efSReza Sabdar if (zfs_release(zhp, p, jname, recursive) != 0) { 231876b86efSReza Sabdar NDMP_LOG(LOG_DEBUG, "Cannot release snapshot %s", p); 232876b86efSReza Sabdar rv = -1; 233876b86efSReza Sabdar } 234876b86efSReza Sabdar if (cleanup_fd != -1) { 235876b86efSReza Sabdar (void) close(cleanup_fd); 236876b86efSReza Sabdar cleanup_fd = -1; 237876b86efSReza Sabdar } 238876b86efSReza Sabdar zfs_close(zhp); 239876b86efSReza Sabdar return (rv); 240876b86efSReza Sabdar } 241876b86efSReza Sabdar 242876b86efSReza Sabdar /* 243876b86efSReza Sabdar * Create a snapshot on the volume 244876b86efSReza Sabdar */ 245876b86efSReza Sabdar int 246876b86efSReza Sabdar snapshot_create(char *volname, char *jname, boolean_t recursive, 247876b86efSReza Sabdar boolean_t hold) 248876b86efSReza Sabdar { 249*40a5c998SMatthew Ahrens char snapname[ZFS_MAX_DATASET_NAME_LEN]; 250876b86efSReza Sabdar int rv; 251876b86efSReza Sabdar 252876b86efSReza Sabdar if (!volname || !*volname) 253876b86efSReza Sabdar return (-1); 254876b86efSReza Sabdar 255*40a5c998SMatthew Ahrens (void) snprintf(snapname, ZFS_MAX_DATASET_NAME_LEN, 256*40a5c998SMatthew Ahrens "%s@%s", volname, jname); 257876b86efSReza Sabdar 258876b86efSReza Sabdar (void) mutex_lock(&zlib_mtx); 259876b86efSReza Sabdar if ((rv = zfs_snapshot(zlibh, snapname, recursive, NULL)) 260876b86efSReza Sabdar == -1) { 261876b86efSReza Sabdar if (errno == EEXIST) { 262876b86efSReza Sabdar (void) mutex_unlock(&zlib_mtx); 263876b86efSReza Sabdar return (0); 264876b86efSReza Sabdar } 265876b86efSReza Sabdar NDMP_LOG(LOG_DEBUG, 266876b86efSReza Sabdar "snapshot_create: %s failed (err=%d): %s", 267876b86efSReza Sabdar snapname, errno, libzfs_error_description(zlibh)); 268876b86efSReza Sabdar (void) mutex_unlock(&zlib_mtx); 269876b86efSReza Sabdar return (rv); 270876b86efSReza Sabdar } 271876b86efSReza Sabdar if (hold && snapshot_hold(volname, snapname, jname, recursive) != 0) { 272876b86efSReza Sabdar NDMP_LOG(LOG_DEBUG, 273876b86efSReza Sabdar "snapshot_create: %s hold failed (err=%d): %s", 274876b86efSReza Sabdar snapname, errno, libzfs_error_description(zlibh)); 275876b86efSReza Sabdar (void) mutex_unlock(&zlib_mtx); 276876b86efSReza Sabdar return (-1); 277876b86efSReza Sabdar } 278876b86efSReza Sabdar 279876b86efSReza Sabdar (void) mutex_unlock(&zlib_mtx); 280876b86efSReza Sabdar return (0); 281876b86efSReza Sabdar } 282876b86efSReza Sabdar 283876b86efSReza Sabdar /* 284876b86efSReza Sabdar * Remove and release the backup snapshot 285876b86efSReza Sabdar */ 286876b86efSReza Sabdar int 287876b86efSReza Sabdar snapshot_destroy(char *volname, char *jname, boolean_t recursive, 288876b86efSReza Sabdar boolean_t hold, int *zfs_err) 289876b86efSReza Sabdar { 290*40a5c998SMatthew Ahrens char snapname[ZFS_MAX_DATASET_NAME_LEN]; 291876b86efSReza Sabdar zfs_handle_t *zhp; 292876b86efSReza Sabdar zfs_type_t ztype; 293588541fbSReza Sabdar char *namep; 294876b86efSReza Sabdar int err; 295876b86efSReza Sabdar 296876b86efSReza Sabdar if (zfs_err) 297876b86efSReza Sabdar *zfs_err = 0; 298876b86efSReza Sabdar 299876b86efSReza Sabdar if (!volname || !*volname) 300876b86efSReza Sabdar return (-1); 301876b86efSReza Sabdar 302876b86efSReza Sabdar if (recursive) { 303876b86efSReza Sabdar ztype = ZFS_TYPE_VOLUME | ZFS_TYPE_FILESYSTEM; 304588541fbSReza Sabdar namep = volname; 305876b86efSReza Sabdar } else { 306*40a5c998SMatthew Ahrens (void) snprintf(snapname, ZFS_MAX_DATASET_NAME_LEN, 307*40a5c998SMatthew Ahrens "%s@%s", volname, jname); 308588541fbSReza Sabdar namep = snapname; 309876b86efSReza Sabdar ztype = ZFS_TYPE_SNAPSHOT; 310876b86efSReza Sabdar } 311876b86efSReza Sabdar 312876b86efSReza Sabdar (void) mutex_lock(&zlib_mtx); 313876b86efSReza Sabdar if (hold && 314588541fbSReza Sabdar snapshot_release(volname, namep, jname, recursive) != 0) { 315876b86efSReza Sabdar NDMP_LOG(LOG_DEBUG, 316876b86efSReza Sabdar "snapshot_destroy: %s release failed (err=%d): %s", 317588541fbSReza Sabdar namep, errno, libzfs_error_description(zlibh)); 318876b86efSReza Sabdar (void) mutex_unlock(&zlib_mtx); 319876b86efSReza Sabdar return (-1); 320876b86efSReza Sabdar } 321876b86efSReza Sabdar 322588541fbSReza Sabdar if ((zhp = zfs_open(zlibh, namep, ztype)) == NULL) { 323876b86efSReza Sabdar NDMP_LOG(LOG_DEBUG, "snapshot_destroy: open %s failed", 324588541fbSReza Sabdar namep); 325876b86efSReza Sabdar (void) mutex_unlock(&zlib_mtx); 326876b86efSReza Sabdar return (-1); 327876b86efSReza Sabdar } 328876b86efSReza Sabdar 329876b86efSReza Sabdar if (recursive) { 330876b86efSReza Sabdar err = zfs_destroy_snaps(zhp, jname, B_TRUE); 331876b86efSReza Sabdar } else { 332876b86efSReza Sabdar err = zfs_destroy(zhp, B_TRUE); 333876b86efSReza Sabdar } 334876b86efSReza Sabdar 335876b86efSReza Sabdar if (err) { 336876b86efSReza Sabdar NDMP_LOG(LOG_ERR, "%s (recursive destroy: %d): %d; %s; %s", 337588541fbSReza Sabdar namep, 338876b86efSReza Sabdar recursive, 339876b86efSReza Sabdar libzfs_errno(zlibh), 340876b86efSReza Sabdar libzfs_error_action(zlibh), 341876b86efSReza Sabdar libzfs_error_description(zlibh)); 342876b86efSReza Sabdar 343876b86efSReza Sabdar if (zfs_err) 344876b86efSReza Sabdar *zfs_err = err; 345876b86efSReza Sabdar } 346876b86efSReza Sabdar 347876b86efSReza Sabdar zfs_close(zhp); 348876b86efSReza Sabdar (void) mutex_unlock(&zlib_mtx); 349876b86efSReza Sabdar 350876b86efSReza Sabdar return (0); 3512654012fSReza Sabdar } 352