17917SReza.Sabdar@Sun.COM /* 212186SJanice.Chang@Sun.COM * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. 37917SReza.Sabdar@Sun.COM */ 47917SReza.Sabdar@Sun.COM 57917SReza.Sabdar@Sun.COM /* 67917SReza.Sabdar@Sun.COM * BSD 3 Clause License 77917SReza.Sabdar@Sun.COM * 87917SReza.Sabdar@Sun.COM * Copyright (c) 2007, The Storage Networking Industry Association. 97917SReza.Sabdar@Sun.COM * 107917SReza.Sabdar@Sun.COM * Redistribution and use in source and binary forms, with or without 117917SReza.Sabdar@Sun.COM * modification, are permitted provided that the following conditions 127917SReza.Sabdar@Sun.COM * are met: 137917SReza.Sabdar@Sun.COM * - Redistributions of source code must retain the above copyright 147917SReza.Sabdar@Sun.COM * notice, this list of conditions and the following disclaimer. 157917SReza.Sabdar@Sun.COM * 167917SReza.Sabdar@Sun.COM * - Redistributions in binary form must reproduce the above copyright 177917SReza.Sabdar@Sun.COM * notice, this list of conditions and the following disclaimer in 187917SReza.Sabdar@Sun.COM * the documentation and/or other materials provided with the 197917SReza.Sabdar@Sun.COM * distribution. 207917SReza.Sabdar@Sun.COM * 217917SReza.Sabdar@Sun.COM * - Neither the name of The Storage Networking Industry Association (SNIA) 227917SReza.Sabdar@Sun.COM * nor the names of its contributors may be used to endorse or promote 237917SReza.Sabdar@Sun.COM * products derived from this software without specific prior written 247917SReza.Sabdar@Sun.COM * permission. 257917SReza.Sabdar@Sun.COM * 267917SReza.Sabdar@Sun.COM * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 277917SReza.Sabdar@Sun.COM * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 287917SReza.Sabdar@Sun.COM * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 297917SReza.Sabdar@Sun.COM * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 307917SReza.Sabdar@Sun.COM * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 317917SReza.Sabdar@Sun.COM * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 327917SReza.Sabdar@Sun.COM * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 337917SReza.Sabdar@Sun.COM * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 347917SReza.Sabdar@Sun.COM * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 357917SReza.Sabdar@Sun.COM * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 367917SReza.Sabdar@Sun.COM * POSSIBILITY OF SUCH DAMAGE. 377917SReza.Sabdar@Sun.COM */ 387917SReza.Sabdar@Sun.COM 397917SReza.Sabdar@Sun.COM #include <stdio.h> 407917SReza.Sabdar@Sun.COM #include <string.h> 417917SReza.Sabdar@Sun.COM #include "ndmpd.h" 427917SReza.Sabdar@Sun.COM #include <libzfs.h> 437917SReza.Sabdar@Sun.COM 44*12904SReza.Sabdar@Sun.COM typedef struct snap_param { 45*12904SReza.Sabdar@Sun.COM char *snp_name; 46*12904SReza.Sabdar@Sun.COM boolean_t snp_found; 47*12904SReza.Sabdar@Sun.COM } snap_param_t; 487917SReza.Sabdar@Sun.COM 49*12904SReza.Sabdar@Sun.COM static int cleanup_fd = -1; 507917SReza.Sabdar@Sun.COM 517917SReza.Sabdar@Sun.COM /* 527917SReza.Sabdar@Sun.COM * ndmp_has_backup 537917SReza.Sabdar@Sun.COM * 547917SReza.Sabdar@Sun.COM * Call backup function which looks for backup snapshot. 557917SReza.Sabdar@Sun.COM * This is a callback function used with zfs_iter_snapshots. 567917SReza.Sabdar@Sun.COM * 577917SReza.Sabdar@Sun.COM * Parameters: 587917SReza.Sabdar@Sun.COM * zhp (input) - ZFS handle pointer 597917SReza.Sabdar@Sun.COM * data (output) - 0 - no backup snapshot 607917SReza.Sabdar@Sun.COM * 1 - has backup snapshot 617917SReza.Sabdar@Sun.COM * 627917SReza.Sabdar@Sun.COM * Returns: 637917SReza.Sabdar@Sun.COM * 0: on success 647917SReza.Sabdar@Sun.COM * -1: otherwise 657917SReza.Sabdar@Sun.COM */ 667917SReza.Sabdar@Sun.COM static int 677917SReza.Sabdar@Sun.COM ndmp_has_backup(zfs_handle_t *zhp, void *data) 687917SReza.Sabdar@Sun.COM { 697917SReza.Sabdar@Sun.COM const char *name; 70*12904SReza.Sabdar@Sun.COM snap_param_t *chp = (snap_param_t *)data; 717917SReza.Sabdar@Sun.COM 727917SReza.Sabdar@Sun.COM name = zfs_get_name(zhp); 737917SReza.Sabdar@Sun.COM if (name == NULL || 74*12904SReza.Sabdar@Sun.COM strstr(name, chp->snp_name) == NULL) { 757917SReza.Sabdar@Sun.COM zfs_close(zhp); 767917SReza.Sabdar@Sun.COM return (-1); 777917SReza.Sabdar@Sun.COM } 787917SReza.Sabdar@Sun.COM 79*12904SReza.Sabdar@Sun.COM chp->snp_found = 1; 807917SReza.Sabdar@Sun.COM zfs_close(zhp); 817917SReza.Sabdar@Sun.COM 827917SReza.Sabdar@Sun.COM return (0); 837917SReza.Sabdar@Sun.COM } 847917SReza.Sabdar@Sun.COM 857917SReza.Sabdar@Sun.COM /* 86*12904SReza.Sabdar@Sun.COM * ndmp_has_backup_snapshot 877917SReza.Sabdar@Sun.COM * 887917SReza.Sabdar@Sun.COM * Returns TRUE if the volume has an active backup snapshot, otherwise, 897917SReza.Sabdar@Sun.COM * returns FALSE. 907917SReza.Sabdar@Sun.COM * 917917SReza.Sabdar@Sun.COM * Parameters: 927917SReza.Sabdar@Sun.COM * volname (input) - name of the volume 937917SReza.Sabdar@Sun.COM * 947917SReza.Sabdar@Sun.COM * Returns: 957917SReza.Sabdar@Sun.COM * 0: on success 967917SReza.Sabdar@Sun.COM * -1: otherwise 977917SReza.Sabdar@Sun.COM */ 987917SReza.Sabdar@Sun.COM static int 99*12904SReza.Sabdar@Sun.COM ndmp_has_backup_snapshot(char *volname, char *jobname) 1007917SReza.Sabdar@Sun.COM { 1017917SReza.Sabdar@Sun.COM zfs_handle_t *zhp; 102*12904SReza.Sabdar@Sun.COM snap_param_t snp; 1037917SReza.Sabdar@Sun.COM char chname[ZFS_MAXNAMELEN]; 1047917SReza.Sabdar@Sun.COM 1057917SReza.Sabdar@Sun.COM (void) mutex_lock(&zlib_mtx); 1067917SReza.Sabdar@Sun.COM if ((zhp = zfs_open(zlibh, volname, ZFS_TYPE_DATASET)) == 0) { 107*12904SReza.Sabdar@Sun.COM NDMP_LOG(LOG_ERR, "Cannot open snapshot %s.", volname); 1087917SReza.Sabdar@Sun.COM (void) mutex_unlock(&zlib_mtx); 1097917SReza.Sabdar@Sun.COM return (-1); 1107917SReza.Sabdar@Sun.COM } 1117917SReza.Sabdar@Sun.COM 112*12904SReza.Sabdar@Sun.COM snp.snp_found = 0; 11312186SJanice.Chang@Sun.COM (void) snprintf(chname, ZFS_MAXNAMELEN, "@%s", jobname); 114*12904SReza.Sabdar@Sun.COM snp.snp_name = chname; 1157917SReza.Sabdar@Sun.COM 116*12904SReza.Sabdar@Sun.COM (void) zfs_iter_snapshots(zhp, ndmp_has_backup, &snp); 1177917SReza.Sabdar@Sun.COM zfs_close(zhp); 1187917SReza.Sabdar@Sun.COM (void) mutex_unlock(&zlib_mtx); 1197917SReza.Sabdar@Sun.COM 120*12904SReza.Sabdar@Sun.COM return (snp.snp_found); 1217917SReza.Sabdar@Sun.COM } 1227917SReza.Sabdar@Sun.COM 1237917SReza.Sabdar@Sun.COM /* 124*12904SReza.Sabdar@Sun.COM * ndmp_create_snapshot 1257917SReza.Sabdar@Sun.COM * 126*12904SReza.Sabdar@Sun.COM * This function will parse the path to get the real volume name. 127*12904SReza.Sabdar@Sun.COM * It will then create a snapshot based on volume and job name. 1287917SReza.Sabdar@Sun.COM * This function should be called before the NDMP backup is started. 1297917SReza.Sabdar@Sun.COM * 1307917SReza.Sabdar@Sun.COM * Parameters: 1317917SReza.Sabdar@Sun.COM * vol_name (input) - name of the volume 1327917SReza.Sabdar@Sun.COM * 1337917SReza.Sabdar@Sun.COM * Returns: 1347917SReza.Sabdar@Sun.COM * 0: on success 1357917SReza.Sabdar@Sun.COM * -1: otherwise 1367917SReza.Sabdar@Sun.COM */ 1377917SReza.Sabdar@Sun.COM int 138*12904SReza.Sabdar@Sun.COM ndmp_create_snapshot(char *vol_name, char *jname) 1397917SReza.Sabdar@Sun.COM { 1407917SReza.Sabdar@Sun.COM char vol[ZFS_MAXNAMELEN]; 1417917SReza.Sabdar@Sun.COM 1427917SReza.Sabdar@Sun.COM if (vol_name == 0 || 1437917SReza.Sabdar@Sun.COM get_zfsvolname(vol, sizeof (vol), vol_name) == -1) 1447917SReza.Sabdar@Sun.COM return (0); 1457917SReza.Sabdar@Sun.COM 146*12904SReza.Sabdar@Sun.COM /* 147*12904SReza.Sabdar@Sun.COM * If there is an old snapshot left from the previous 148*12904SReza.Sabdar@Sun.COM * backup it could be stale one and it must be 149*12904SReza.Sabdar@Sun.COM * removed before using it. 150*12904SReza.Sabdar@Sun.COM */ 151*12904SReza.Sabdar@Sun.COM if (ndmp_has_backup_snapshot(vol, jname)) 152*12904SReza.Sabdar@Sun.COM (void) snapshot_destroy(vol, jname, B_FALSE, B_TRUE, NULL); 1537917SReza.Sabdar@Sun.COM 154*12904SReza.Sabdar@Sun.COM return (snapshot_create(vol, jname, B_FALSE, B_TRUE)); 1557917SReza.Sabdar@Sun.COM } 1567917SReza.Sabdar@Sun.COM 1577917SReza.Sabdar@Sun.COM /* 158*12904SReza.Sabdar@Sun.COM * ndmp_remove_snapshot 1597917SReza.Sabdar@Sun.COM * 160*12904SReza.Sabdar@Sun.COM * This function will parse the path to get the real volume name. 161*12904SReza.Sabdar@Sun.COM * It will then remove the snapshot for that volume and job name. 1627917SReza.Sabdar@Sun.COM * This function should be called after NDMP backup is finished. 1637917SReza.Sabdar@Sun.COM * 1647917SReza.Sabdar@Sun.COM * Parameters: 1657917SReza.Sabdar@Sun.COM * vol_name (input) - name of the volume 1667917SReza.Sabdar@Sun.COM * 1677917SReza.Sabdar@Sun.COM * Returns: 1687917SReza.Sabdar@Sun.COM * 0: on success 1697917SReza.Sabdar@Sun.COM * -1: otherwise 1707917SReza.Sabdar@Sun.COM */ 1717917SReza.Sabdar@Sun.COM int 172*12904SReza.Sabdar@Sun.COM ndmp_remove_snapshot(char *vol_name, char *jname) 1737917SReza.Sabdar@Sun.COM { 1747917SReza.Sabdar@Sun.COM char vol[ZFS_MAXNAMELEN]; 1757917SReza.Sabdar@Sun.COM 1767917SReza.Sabdar@Sun.COM if (vol_name == 0 || 177*12904SReza.Sabdar@Sun.COM get_zfsvolname(vol, sizeof (vol), vol_name) == -1) 1787917SReza.Sabdar@Sun.COM return (0); 1797917SReza.Sabdar@Sun.COM 180*12904SReza.Sabdar@Sun.COM return (snapshot_destroy(vol, jname, B_FALSE, B_TRUE, NULL)); 181*12904SReza.Sabdar@Sun.COM } 182*12904SReza.Sabdar@Sun.COM 183*12904SReza.Sabdar@Sun.COM /* 184*12904SReza.Sabdar@Sun.COM * Put a hold on snapshot 185*12904SReza.Sabdar@Sun.COM */ 186*12904SReza.Sabdar@Sun.COM int 187*12904SReza.Sabdar@Sun.COM snapshot_hold(char *volname, char *snapname, char *jname, boolean_t recursive) 188*12904SReza.Sabdar@Sun.COM { 189*12904SReza.Sabdar@Sun.COM zfs_handle_t *zhp; 190*12904SReza.Sabdar@Sun.COM char *p; 191*12904SReza.Sabdar@Sun.COM 192*12904SReza.Sabdar@Sun.COM if ((zhp = zfs_open(zlibh, volname, ZFS_TYPE_DATASET)) == 0) { 193*12904SReza.Sabdar@Sun.COM NDMP_LOG(LOG_ERR, "Cannot open volume %s.", volname); 194*12904SReza.Sabdar@Sun.COM return (-1); 195*12904SReza.Sabdar@Sun.COM } 196*12904SReza.Sabdar@Sun.COM 197*12904SReza.Sabdar@Sun.COM if (cleanup_fd == -1 && (cleanup_fd = open(ZFS_DEV, 198*12904SReza.Sabdar@Sun.COM O_RDWR|O_EXCL)) < 0) { 199*12904SReza.Sabdar@Sun.COM NDMP_LOG(LOG_ERR, "Cannot open dev %d", errno); 200*12904SReza.Sabdar@Sun.COM zfs_close(zhp); 201*12904SReza.Sabdar@Sun.COM return (-1); 202*12904SReza.Sabdar@Sun.COM } 203*12904SReza.Sabdar@Sun.COM 204*12904SReza.Sabdar@Sun.COM p = strchr(snapname, '@') + 1; 205*12904SReza.Sabdar@Sun.COM if (zfs_hold(zhp, p, jname, recursive, B_TRUE, B_FALSE, 206*12904SReza.Sabdar@Sun.COM cleanup_fd, 0, 0) != 0) { 207*12904SReza.Sabdar@Sun.COM NDMP_LOG(LOG_ERR, "Cannot hold snapshot %s", p); 208*12904SReza.Sabdar@Sun.COM zfs_close(zhp); 209*12904SReza.Sabdar@Sun.COM return (-1); 210*12904SReza.Sabdar@Sun.COM } 211*12904SReza.Sabdar@Sun.COM zfs_close(zhp); 212*12904SReza.Sabdar@Sun.COM return (0); 213*12904SReza.Sabdar@Sun.COM } 214*12904SReza.Sabdar@Sun.COM 215*12904SReza.Sabdar@Sun.COM int 216*12904SReza.Sabdar@Sun.COM snapshot_release(char *volname, char *snapname, char *jname, 217*12904SReza.Sabdar@Sun.COM boolean_t recursive) 218*12904SReza.Sabdar@Sun.COM { 219*12904SReza.Sabdar@Sun.COM zfs_handle_t *zhp; 220*12904SReza.Sabdar@Sun.COM char *p; 221*12904SReza.Sabdar@Sun.COM int rv = 0; 222*12904SReza.Sabdar@Sun.COM 223*12904SReza.Sabdar@Sun.COM if ((zhp = zfs_open(zlibh, volname, ZFS_TYPE_DATASET)) == 0) { 224*12904SReza.Sabdar@Sun.COM NDMP_LOG(LOG_ERR, "Cannot open volume %s", volname); 225*12904SReza.Sabdar@Sun.COM return (-1); 226*12904SReza.Sabdar@Sun.COM } 227*12904SReza.Sabdar@Sun.COM 228*12904SReza.Sabdar@Sun.COM p = strchr(snapname, '@') + 1; 229*12904SReza.Sabdar@Sun.COM if (zfs_release(zhp, p, jname, recursive) != 0) { 230*12904SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG, "Cannot release snapshot %s", p); 231*12904SReza.Sabdar@Sun.COM rv = -1; 232*12904SReza.Sabdar@Sun.COM } 233*12904SReza.Sabdar@Sun.COM if (cleanup_fd != -1) { 234*12904SReza.Sabdar@Sun.COM (void) close(cleanup_fd); 235*12904SReza.Sabdar@Sun.COM cleanup_fd = -1; 236*12904SReza.Sabdar@Sun.COM } 237*12904SReza.Sabdar@Sun.COM zfs_close(zhp); 238*12904SReza.Sabdar@Sun.COM return (rv); 239*12904SReza.Sabdar@Sun.COM } 240*12904SReza.Sabdar@Sun.COM 241*12904SReza.Sabdar@Sun.COM /* 242*12904SReza.Sabdar@Sun.COM * Create a snapshot on the volume 243*12904SReza.Sabdar@Sun.COM */ 244*12904SReza.Sabdar@Sun.COM int 245*12904SReza.Sabdar@Sun.COM snapshot_create(char *volname, char *jname, boolean_t recursive, 246*12904SReza.Sabdar@Sun.COM boolean_t hold) 247*12904SReza.Sabdar@Sun.COM { 248*12904SReza.Sabdar@Sun.COM char snapname[ZFS_MAXNAMELEN]; 249*12904SReza.Sabdar@Sun.COM int rv; 250*12904SReza.Sabdar@Sun.COM 251*12904SReza.Sabdar@Sun.COM if (!volname || !*volname) 252*12904SReza.Sabdar@Sun.COM return (-1); 253*12904SReza.Sabdar@Sun.COM 254*12904SReza.Sabdar@Sun.COM (void) snprintf(snapname, ZFS_MAXNAMELEN, "%s@%s", volname, jname); 2557917SReza.Sabdar@Sun.COM 256*12904SReza.Sabdar@Sun.COM (void) mutex_lock(&zlib_mtx); 257*12904SReza.Sabdar@Sun.COM if ((rv = zfs_snapshot(zlibh, snapname, recursive, NULL)) 258*12904SReza.Sabdar@Sun.COM == -1) { 259*12904SReza.Sabdar@Sun.COM if (errno == EEXIST) { 260*12904SReza.Sabdar@Sun.COM (void) mutex_unlock(&zlib_mtx); 261*12904SReza.Sabdar@Sun.COM return (0); 262*12904SReza.Sabdar@Sun.COM } 263*12904SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG, 264*12904SReza.Sabdar@Sun.COM "snapshot_create: %s failed (err=%d): %s", 265*12904SReza.Sabdar@Sun.COM snapname, errno, libzfs_error_description(zlibh)); 266*12904SReza.Sabdar@Sun.COM (void) mutex_unlock(&zlib_mtx); 267*12904SReza.Sabdar@Sun.COM return (rv); 268*12904SReza.Sabdar@Sun.COM } 269*12904SReza.Sabdar@Sun.COM if (hold && snapshot_hold(volname, snapname, jname, recursive) != 0) { 270*12904SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG, 271*12904SReza.Sabdar@Sun.COM "snapshot_create: %s hold failed (err=%d): %s", 272*12904SReza.Sabdar@Sun.COM snapname, errno, libzfs_error_description(zlibh)); 273*12904SReza.Sabdar@Sun.COM (void) mutex_unlock(&zlib_mtx); 274*12904SReza.Sabdar@Sun.COM return (-1); 275*12904SReza.Sabdar@Sun.COM } 276*12904SReza.Sabdar@Sun.COM 277*12904SReza.Sabdar@Sun.COM (void) mutex_unlock(&zlib_mtx); 278*12904SReza.Sabdar@Sun.COM return (0); 2797917SReza.Sabdar@Sun.COM } 280*12904SReza.Sabdar@Sun.COM 281*12904SReza.Sabdar@Sun.COM /* 282*12904SReza.Sabdar@Sun.COM * Remove and release the backup snapshot 283*12904SReza.Sabdar@Sun.COM */ 284*12904SReza.Sabdar@Sun.COM int 285*12904SReza.Sabdar@Sun.COM snapshot_destroy(char *volname, char *jname, boolean_t recursive, 286*12904SReza.Sabdar@Sun.COM boolean_t hold, int *zfs_err) 287*12904SReza.Sabdar@Sun.COM { 288*12904SReza.Sabdar@Sun.COM char snapname[ZFS_MAXNAMELEN]; 289*12904SReza.Sabdar@Sun.COM zfs_handle_t *zhp; 290*12904SReza.Sabdar@Sun.COM zfs_type_t ztype; 291*12904SReza.Sabdar@Sun.COM int err; 292*12904SReza.Sabdar@Sun.COM 293*12904SReza.Sabdar@Sun.COM if (zfs_err) 294*12904SReza.Sabdar@Sun.COM *zfs_err = 0; 295*12904SReza.Sabdar@Sun.COM 296*12904SReza.Sabdar@Sun.COM if (!volname || !*volname) 297*12904SReza.Sabdar@Sun.COM return (-1); 298*12904SReza.Sabdar@Sun.COM 299*12904SReza.Sabdar@Sun.COM if (recursive) { 300*12904SReza.Sabdar@Sun.COM ztype = ZFS_TYPE_VOLUME | ZFS_TYPE_FILESYSTEM; 301*12904SReza.Sabdar@Sun.COM } else { 302*12904SReza.Sabdar@Sun.COM (void) snprintf(snapname, ZFS_MAXNAMELEN, "%s@%s", volname, 303*12904SReza.Sabdar@Sun.COM jname); 304*12904SReza.Sabdar@Sun.COM ztype = ZFS_TYPE_SNAPSHOT; 305*12904SReza.Sabdar@Sun.COM } 306*12904SReza.Sabdar@Sun.COM 307*12904SReza.Sabdar@Sun.COM (void) mutex_lock(&zlib_mtx); 308*12904SReza.Sabdar@Sun.COM if (hold && 309*12904SReza.Sabdar@Sun.COM snapshot_release(volname, snapname, jname, recursive) != 0) { 310*12904SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG, 311*12904SReza.Sabdar@Sun.COM "snapshot_destroy: %s release failed (err=%d): %s", 312*12904SReza.Sabdar@Sun.COM snapname, errno, libzfs_error_description(zlibh)); 313*12904SReza.Sabdar@Sun.COM (void) mutex_unlock(&zlib_mtx); 314*12904SReza.Sabdar@Sun.COM return (-1); 315*12904SReza.Sabdar@Sun.COM } 316*12904SReza.Sabdar@Sun.COM 317*12904SReza.Sabdar@Sun.COM if ((zhp = zfs_open(zlibh, snapname, ztype)) == NULL) { 318*12904SReza.Sabdar@Sun.COM NDMP_LOG(LOG_DEBUG, "snapshot_destroy: open %s failed", 319*12904SReza.Sabdar@Sun.COM snapname); 320*12904SReza.Sabdar@Sun.COM (void) mutex_unlock(&zlib_mtx); 321*12904SReza.Sabdar@Sun.COM return (-1); 322*12904SReza.Sabdar@Sun.COM } 323*12904SReza.Sabdar@Sun.COM 324*12904SReza.Sabdar@Sun.COM if (recursive) { 325*12904SReza.Sabdar@Sun.COM err = zfs_destroy_snaps(zhp, jname, B_TRUE); 326*12904SReza.Sabdar@Sun.COM } else { 327*12904SReza.Sabdar@Sun.COM err = zfs_destroy(zhp, B_TRUE); 328*12904SReza.Sabdar@Sun.COM } 329*12904SReza.Sabdar@Sun.COM 330*12904SReza.Sabdar@Sun.COM if (err) { 331*12904SReza.Sabdar@Sun.COM NDMP_LOG(LOG_ERR, "%s (recursive destroy: %d): %d; %s; %s", 332*12904SReza.Sabdar@Sun.COM snapname, 333*12904SReza.Sabdar@Sun.COM recursive, 334*12904SReza.Sabdar@Sun.COM libzfs_errno(zlibh), 335*12904SReza.Sabdar@Sun.COM libzfs_error_action(zlibh), 336*12904SReza.Sabdar@Sun.COM libzfs_error_description(zlibh)); 337*12904SReza.Sabdar@Sun.COM 338*12904SReza.Sabdar@Sun.COM if (zfs_err) 339*12904SReza.Sabdar@Sun.COM *zfs_err = err; 340*12904SReza.Sabdar@Sun.COM } 341*12904SReza.Sabdar@Sun.COM 342*12904SReza.Sabdar@Sun.COM zfs_close(zhp); 343*12904SReza.Sabdar@Sun.COM (void) mutex_unlock(&zlib_mtx); 344*12904SReza.Sabdar@Sun.COM 345*12904SReza.Sabdar@Sun.COM return (0); 346*12904SReza.Sabdar@Sun.COM } 347