Print this page
NEX-13374 NDMP should be able to backup unmounted ZFS filesystems
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-5801 Snapshots left over after failed backups
Reviewed by: Rick Mesta <rick.mesta@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Revert "NEX-5801 Snapshots left over after failed backups"
This reverts commit f182fb95f09036db71fbfc6f0a6b90469b761f21.
NEX-5801 Snapshots left over after failed backups
Reviewed by: Rick Mesta <rick.mesta@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
NEX-2911 NDMP logging should use syslog and is too chatty
   1 /*
   2  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
   3  * Copyright (c) 2013, 2015 by Delphix. All rights reserved.
   4  * Copyright (c) 2013 Steven Hartland. All rights reserved.
   5  * Copyright (c) 2016 Martin Matuska. All rights reserved.

   6  */
   7 
   8 /*
   9  * BSD 3 Clause License
  10  *
  11  * Copyright (c) 2007, The Storage Networking Industry Association.
  12  *
  13  * Redistribution and use in source and binary forms, with or without
  14  * modification, are permitted provided that the following conditions
  15  * are met:
  16  *      - Redistributions of source code must retain the above copyright
  17  *        notice, this list of conditions and the following disclaimer.
  18  *
  19  *      - Redistributions in binary form must reproduce the above copyright
  20  *        notice, this list of conditions and the following disclaimer in
  21  *        the documentation and/or other materials provided with the
  22  *        distribution.
  23  *
  24  *      - Neither the name of The Storage Networking Industry Association (SNIA)
  25  *        nor the names of its contributors may be used to endorse or promote
  26  *        products derived from this software without specific prior written
  27  *        permission.
  28  *
  29  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  30  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  31  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  32  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  33  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  34  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  35  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  36  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  37  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  38  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  39  * POSSIBILITY OF SUCH DAMAGE.
  40  */
  41 

  42 #include <stdio.h>
  43 #include <string.h>

  44 #include "ndmpd.h"
  45 #include <libzfs.h>
  46 
  47 typedef struct snap_param {
  48         char *snp_name;
  49         boolean_t snp_found;
  50 } snap_param_t;
  51 
  52 static int cleanup_fd = -1;
  53 
  54 /*
  55  * ndmp_has_backup
  56  *
  57  * Call backup function which looks for backup snapshot.
  58  * This is a callback function used with zfs_iter_snapshots.
  59  *
  60  * Parameters:
  61  *   zhp (input) - ZFS handle pointer
  62  *   data (output) - 0 - no backup snapshot
  63  *                   1 - has backup snapshot
  64  *
  65  * Returns:
  66  *   0: on success
  67  *  -1: otherwise
  68  */
  69 static int
  70 ndmp_has_backup(zfs_handle_t *zhp, void *data)
  71 {
  72         const char *name;
  73         snap_param_t *chp = (snap_param_t *)data;
  74 
  75         name = zfs_get_name(zhp);
  76         if (name == NULL ||
  77             strstr(name, chp->snp_name) == NULL) {
  78                 zfs_close(zhp);
  79                 return (-1);
  80         }
  81 
  82         chp->snp_found = 1;
  83         zfs_close(zhp);
  84 
  85         return (0);
  86 }
  87 
  88 /*
  89  * ndmp_has_backup_snapshot
  90  *
  91  * Returns TRUE if the volume has an active backup snapshot, otherwise,
  92  * returns FALSE.
  93  *
  94  * Parameters:
  95  *   volname (input) - name of the volume
  96  *
  97  * Returns:
  98  *   0: on success
  99  *  -1: otherwise
 100  */
 101 static int
 102 ndmp_has_backup_snapshot(char *volname, char *jobname)
 103 {
 104         zfs_handle_t *zhp;
 105         snap_param_t snp;
 106         char chname[ZFS_MAX_DATASET_NAME_LEN];
 107 
 108         (void) mutex_lock(&zlib_mtx);
 109         if ((zhp = zfs_open(zlibh, volname, ZFS_TYPE_DATASET)) == 0) {
 110                 NDMP_LOG(LOG_ERR, "Cannot open snapshot %s.", volname);
 111                 (void) mutex_unlock(&zlib_mtx);
 112                 return (-1);
 113         }
 114 
 115         snp.snp_found = 0;
 116         (void) snprintf(chname, ZFS_MAX_DATASET_NAME_LEN, "@%s", jobname);
 117         snp.snp_name = chname;
 118 
 119         (void) zfs_iter_snapshots(zhp, B_FALSE, ndmp_has_backup, &snp);
 120         zfs_close(zhp);
 121         (void) mutex_unlock(&zlib_mtx);
 122 
 123         return (snp.snp_found);
 124 }
 125 
 126 /*
 127  * ndmp_create_snapshot
 128  *
 129  * This function will parse the path to get the real volume name.
 130  * It will then create a snapshot based on volume and job name.
 131  * This function should be called before the NDMP backup is started.
 132  *
 133  * Parameters:
 134  *   vol_name (input) - name of the volume
 135  *
 136  * Returns:
 137  *   0: on success
 138  *   -1: otherwise
 139  */
 140 int
 141 ndmp_create_snapshot(char *vol_name, char *jname)
 142 {
 143         char vol[ZFS_MAX_DATASET_NAME_LEN];
 144 
 145         if (vol_name == 0 ||
 146             get_zfsvolname(vol, sizeof (vol), vol_name) == -1)
 147                 return (0);
 148 
 149         /*
 150          * If there is an old snapshot left from the previous
 151          * backup it could be stale one and it must be
 152          * removed before using it.
 153          */
 154         if (ndmp_has_backup_snapshot(vol, jname))
 155                 (void) snapshot_destroy(vol, jname, B_FALSE, B_TRUE, NULL);
 156 
 157         return (snapshot_create(vol, jname, B_FALSE, B_TRUE));
 158 }
 159 
 160 /*
 161  * ndmp_remove_snapshot
 162  *
 163  * This function will parse the path to get the real volume name.
 164  * It will then remove the snapshot for that volume and job name.
 165  * This function should be called after NDMP backup is finished.
 166  *
 167  * Parameters:
 168  *   vol_name (input) - name of the volume
 169  *
 170  * Returns:
 171  *   0: on success
 172  *   -1: otherwise
 173  */
 174 int
 175 ndmp_remove_snapshot(char *vol_name, char *jname)
 176 {
 177         char vol[ZFS_MAX_DATASET_NAME_LEN];
 178 
 179         if (vol_name == 0 ||
 180             get_zfsvolname(vol, sizeof (vol), vol_name) == -1)
 181                 return (0);
 182 
 183         return (snapshot_destroy(vol, jname, B_FALSE, B_TRUE, NULL));
 184 }
 185 
 186 /*
 187  * Put a hold on snapshot
 188  */
 189 int
 190 snapshot_hold(char *volname, char *snapname, char *jname, boolean_t recursive)
 191 {
 192         zfs_handle_t *zhp;
 193         char *p;
 194 
 195         if ((zhp = zfs_open(zlibh, volname, ZFS_TYPE_DATASET)) == 0) {
 196                 NDMP_LOG(LOG_ERR, "Cannot open volume %s.", volname);
 197                 return (-1);
 198         }
 199 
 200         if (cleanup_fd == -1 && (cleanup_fd = open(ZFS_DEV,
 201             O_RDWR|O_EXCL)) < 0) {
 202                 NDMP_LOG(LOG_ERR, "Cannot open dev %d", errno);
 203                 zfs_close(zhp);
 204                 return (-1);
 205         }
 206 
 207         p = strchr(snapname, '@') + 1;
 208         if (zfs_hold(zhp, p, jname, recursive, cleanup_fd) != 0) {
 209                 NDMP_LOG(LOG_ERR, "Cannot hold snapshot %s", p);




 210                 zfs_close(zhp);
 211                 return (-1);
 212         }
 213         zfs_close(zhp);
 214         return (0);
 215 }
 216 
 217 int
 218 snapshot_release(char *volname, char *snapname, char *jname,
 219     boolean_t recursive)
 220 {
 221         zfs_handle_t *zhp;
 222         char *p;
 223         int rv = 0;
 224 
 225         if ((zhp = zfs_open(zlibh, volname, ZFS_TYPE_DATASET)) == 0) {
 226                 NDMP_LOG(LOG_ERR, "Cannot open volume %s", volname);
 227                 return (-1);
 228         }
 229 
 230         p = strchr(snapname, '@') + 1;
 231         if (zfs_release(zhp, p, jname, recursive) != 0) {
 232                 NDMP_LOG(LOG_DEBUG, "Cannot release snapshot %s", p);
 233                 rv = -1;
 234         }
 235         if (cleanup_fd != -1) {
 236                 (void) close(cleanup_fd);
 237                 cleanup_fd = -1;
 238         }
 239         zfs_close(zhp);
 240         return (rv);
 241 }
 242 
 243 /*
 244  * Create a snapshot on the volume


 245  */
 246 int
 247 snapshot_create(char *volname, char *jname, boolean_t recursive,
 248     boolean_t hold)
 249 {
 250         char snapname[ZFS_MAX_DATASET_NAME_LEN];

 251         int rv;
 252 
 253         if (!volname || !*volname)
 254                 return (-1);

 255 
 256         (void) snprintf(snapname, ZFS_MAX_DATASET_NAME_LEN,
 257             "%s@%s", volname, jname);







 258 



 259         (void) mutex_lock(&zlib_mtx);
 260         if ((rv = zfs_snapshot(zlibh, snapname, recursive, NULL))
 261             == -1) {











 262                 if (errno == EEXIST) {
 263                         (void) mutex_unlock(&zlib_mtx);
 264                         return (0);
 265                 }
 266                 NDMP_LOG(LOG_DEBUG,
 267                     "snapshot_create: %s failed (err=%d): %s",
 268                     snapname, errno, libzfs_error_description(zlibh));

 269                 (void) mutex_unlock(&zlib_mtx);
 270                 return (rv);
 271         }
 272         if (hold && snapshot_hold(volname, snapname, jname, recursive) != 0) {
 273                 NDMP_LOG(LOG_DEBUG,
 274                     "snapshot_create: %s hold failed (err=%d): %s",
 275                     snapname, errno, libzfs_error_description(zlibh));



 276                 (void) mutex_unlock(&zlib_mtx);
 277                 return (-1);
 278         }



 279 






 280         (void) mutex_unlock(&zlib_mtx);



 281         return (0);
 282 }
 283 
 284 /*
 285  * Remove and release the backup snapshot
 286  */
 287 int
 288 snapshot_destroy(char *volname, char *jname, boolean_t recursive,
 289     boolean_t hold, int *zfs_err)
 290 {
 291         char snapname[ZFS_MAX_DATASET_NAME_LEN];
 292         zfs_handle_t *zhp;
 293         zfs_type_t ztype;
 294         char *namep;
 295         int err;

 296 
 297         if (zfs_err)
 298                 *zfs_err = 0;
 299 
 300         if (!volname || !*volname)
 301                 return (-1);

 302 
 303         if (recursive) {
 304                 ztype = ZFS_TYPE_VOLUME | ZFS_TYPE_FILESYSTEM;
 305                 namep = volname;
 306         } else {
 307                 (void) snprintf(snapname, ZFS_MAX_DATASET_NAME_LEN,
 308                     "%s@%s", volname, jname);
 309                 namep = snapname;
 310                 ztype = ZFS_TYPE_SNAPSHOT;
 311         }
 312 















 313         (void) mutex_lock(&zlib_mtx);
 314         if (hold &&
 315             snapshot_release(volname, namep, jname, recursive) != 0) {
 316                 NDMP_LOG(LOG_DEBUG,
 317                     "snapshot_destroy: %s release failed (err=%d): %s",
 318                     namep, errno, libzfs_error_description(zlibh));









 319                 (void) mutex_unlock(&zlib_mtx);
 320                 return (-1);
 321         }




 322 
 323         if ((zhp = zfs_open(zlibh, namep, ztype)) == NULL) {
 324                 NDMP_LOG(LOG_DEBUG, "snapshot_destroy: open %s failed",
 325                     namep);





 326                 (void) mutex_unlock(&zlib_mtx);
 327                 return (-1);
 328         }
 329 
 330         if (recursive) {
 331                 err = zfs_destroy_snaps(zhp, jname, B_TRUE);
 332         } else {
 333                 err = zfs_destroy(zhp, B_TRUE);







 334         }
 335 













 336         if (err) {
 337                 NDMP_LOG(LOG_ERR, "%s (recursive destroy: %d): %d; %s; %s",
 338                     namep,
 339                     recursive,
 340                     libzfs_errno(zlibh),
 341                     libzfs_error_action(zlibh),
 342                     libzfs_error_description(zlibh));



 343 
 344                 if (zfs_err)
 345                         *zfs_err = err;














 346         }




 347 
 348         zfs_close(zhp);


 349         (void) mutex_unlock(&zlib_mtx);
 350 
 351         return (0);













 352 }
   1 /*
   2  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
   3  * Copyright (c) 2013, 2015 by Delphix. All rights reserved.
   4  * Copyright (c) 2013 Steven Hartland. All rights reserved.
   5  * Copyright (c) 2016 Martin Matuska. All rights reserved.
   6  * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
   7  */
   8 
   9 /*
  10  * BSD 3 Clause License
  11  *
  12  * Copyright (c) 2007, The Storage Networking Industry Association.
  13  *
  14  * Redistribution and use in source and binary forms, with or without
  15  * modification, are permitted provided that the following conditions
  16  * are met:
  17  *      - Redistributions of source code must retain the above copyright
  18  *        notice, this list of conditions and the following disclaimer.
  19  *
  20  *      - Redistributions in binary form must reproduce the above copyright
  21  *        notice, this list of conditions and the following disclaimer in
  22  *        the documentation and/or other materials provided with the
  23  *        distribution.
  24  *
  25  *      - Neither the name of The Storage Networking Industry Association (SNIA)
  26  *        nor the names of its contributors may be used to endorse or promote
  27  *        products derived from this software without specific prior written
  28  *        permission.
  29  *
  30  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  31  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  32  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  33  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  34  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  35  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  36  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  37  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  38  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  39  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  40  * POSSIBILITY OF SUCH DAMAGE.
  41  */
  42 
  43 #include <syslog.h>
  44 #include <stdio.h>
  45 #include <string.h>
  46 #include <sys/mount.h>
  47 #include "ndmpd.h"
  48 #include <libzfs.h>
  49 







  50 /*




































































































































  51  * Put a hold on snapshot
  52  */
  53 int
  54 snapshot_hold(char *volname, char *snapname, char *jname)
  55 {
  56         zfs_handle_t *zhp;
  57         char *p;
  58 
  59         if ((zhp = zfs_open(zlibh, volname, ZFS_TYPE_DATASET)) == 0) {
  60                 syslog(LOG_ERR, "Cannot open volume %s.", volname);
  61                 return (-1);
  62         }








  63         p = strchr(snapname, '@') + 1;
  64         /*
  65          * The -1 tells the lower levels there are no snapshots
  66          * to clean up.
  67          */
  68         if (zfs_hold(zhp, p, jname, B_FALSE, -1) != 0) {
  69                 syslog(LOG_ERR, "Cannot hold snapshot %s", p);
  70                 zfs_close(zhp);
  71                 return (-1);
  72         }
  73         zfs_close(zhp);
  74         return (0);
  75 }
  76 
  77 int
  78 snapshot_release(char *volname, char *snapname, char *jname)

  79 {
  80         zfs_handle_t *zhp;
  81         char *p;
  82         int rv = 0;
  83 
  84         if ((zhp = zfs_open(zlibh, volname, ZFS_TYPE_DATASET)) == 0) {
  85                 syslog(LOG_ERR, "Cannot open volume %s", volname);
  86                 return (-1);
  87         }
  88 
  89         p = strchr(snapname, '@') + 1;
  90         if (zfs_release(zhp, p, jname, B_FALSE) != 0) {
  91                 syslog(LOG_DEBUG, "Cannot release snapshot %s", p);
  92                 rv = -1;
  93         }




  94         zfs_close(zhp);
  95         return (rv);
  96 }
  97 
  98 /*
  99  * Create a snapshot, put a hold on it, clone it, and mount it in a
 100  * well known location for so the backup process can traverse its
 101  * directory tree structure.
 102  */
 103 int
 104 backup_dataset_create(ndmp_lbr_params_t *nlp)

 105 {
 106         char zpoolname[ZFS_MAX_DATASET_NAME_LEN];
 107         char *slash;
 108         int rv;
 109 
 110         if (nlp == NULL) {
 111                 return (-1);
 112         }
 113 
 114         (void) strlcpy(zpoolname, nlp->nlp_vol, sizeof (zpoolname));
 115         /*
 116          * Pull out the pool name component from the volname
 117          * to use it to build snapshot and clone names.
 118          */
 119         slash = strchr(zpoolname, '/');
 120         if (slash != NULL) {
 121                 *slash = '\0';
 122         }
 123 
 124         (void) snprintf(nlp->nlp_clonename, sizeof (nlp->nlp_clonename),
 125             "%s/%s", zpoolname, nlp->nlp_job_name);
 126 
 127         (void) mutex_lock(&zlib_mtx);
 128 
 129         /*
 130          * If "checkpoint" is not enabled, create the normal
 131          * snapshot and continue normal backup.  If it is
 132          * enabled, the "checkpoint" name has been already set
 133          * so we just have to clone it.
 134          */
 135         if (!NLP_ISCHKPNTED(nlp)) {
 136                 (void) snprintf(nlp->nlp_snapname, sizeof (nlp->nlp_snapname),
 137                     "%s@%s", nlp->nlp_vol, nlp->nlp_job_name);
 138 
 139                 if ((rv = zfs_snapshot(zlibh, nlp->nlp_snapname,
 140                     B_FALSE, NULL)) != 0) {
 141                         if (errno == EEXIST) {
 142                                 (void) mutex_unlock(&zlib_mtx);
 143                                 return (0);
 144                         }
 145                         syslog(LOG_ERR,
 146                             "backup_dataset_create: %s failed (err=%d): %s",
 147                             nlp->nlp_snapname, errno,
 148                             libzfs_error_description(zlibh));
 149                         (void) mutex_unlock(&zlib_mtx);
 150                         return (rv);
 151                 }
 152                 if (snapshot_hold(nlp->nlp_vol,
 153                     nlp->nlp_snapname, NDMP_RCF_BASENAME) != 0) {
 154                         syslog(LOG_DEBUG,
 155                             "backup_dataset_create: %s "
 156                             "hold failed (err=%d): %s",
 157                             nlp->nlp_snapname,
 158                             errno, libzfs_error_description(zlibh));
 159                         (void) mutex_unlock(&zlib_mtx);
 160                         return (-1);
 161                 }
 162                 syslog(LOG_DEBUG,
 163                     "Using %s NdmpBackup snapshot for backup",
 164                     nlp->nlp_snapname);
 165 
 166         }
 167 
 168         if (ndmp_clone_snapshot(nlp) != 0) {
 169                 syslog(LOG_ERR,
 170                     "backup_dataset_create: %s clone failed (err=%d): %s",
 171                     nlp->nlp_snapname, errno, libzfs_error_description(zlibh));
 172                 (void) mutex_unlock(&zlib_mtx);
 173                 return (-1);
 174         }
 175         (void) mutex_unlock(&zlib_mtx);
 176         return (0);
 177 }
 178 
 179 /*
 180  * Unmount, release, and destroy the snapshot created for backup.
 181  */
 182 int
 183 backup_dataset_destroy(ndmp_lbr_params_t *nlp)

 184 {
 185         char zpoolname[ZFS_MAX_DATASET_NAME_LEN];
 186         char *slash;
 187         zfs_handle_t *vol_zhp;
 188         zfs_handle_t *cln_zhp;
 189         int err;
 190         int rv = 0;
 191 
 192         if (nlp == NULL) {
 193                 syslog(LOG_DEBUG,
 194                     "nlp NULL in backup_dataset_destroy");

 195                 return (-1);
 196         }
 197 
 198         (void) strlcpy(zpoolname, nlp->nlp_vol, sizeof (zpoolname));
 199         slash = strchr(zpoolname, '/');
 200         if (slash != NULL) {
 201                 *slash = '\0';




 202         }
 203 
 204         if (!NLP_ISCHKPNTED(nlp)) {
 205                 (void) snprintf(nlp->nlp_snapname, sizeof (nlp->nlp_snapname),
 206                     "%s@%s", nlp->nlp_vol, nlp->nlp_job_name);
 207         }
 208 
 209 
 210         syslog(LOG_DEBUG, "Snapname in backup_dataset_destroy is [%s]",
 211             nlp->nlp_snapname);
 212 
 213         /*
 214          * Destroy using this sequence
 215          * zfs release <volume>@<jname>
 216          * zfs destroy <pool>/<jname>
 217          * zfs destroy <pool>/<volume>@<jname>
 218          */
 219         (void) mutex_lock(&zlib_mtx);
 220 
 221         /*
 222          * Release the normal snapshot but don't try to
 223          * release if it's a "checkpoint" because the hold
 224          * wasn't put on it to begin with.
 225          */
 226         if (!NLP_ISCHKPNTED(nlp)) {
 227                 if (snapshot_release(nlp->nlp_vol,
 228                     nlp->nlp_snapname, NDMP_RCF_BASENAME) != 0) {
 229                         syslog(LOG_DEBUG,
 230                             "backup_dataset_destroy: %s "
 231                             "release failed (err=%d): %s",
 232                             nlp->nlp_clonename, errno,
 233                             libzfs_error_description(zlibh));
 234                         (void) mutex_unlock(&zlib_mtx);
 235                         return (-1);
 236                 }
 237         } else {
 238                 syslog(LOG_DEBUG, "Checkpointed dataset not held "
 239                     "will not release [%s]", nlp->nlp_snapname);
 240         }
 241 
 242         /*
 243          * Open the clone to get descriptor
 244          */
 245         if ((cln_zhp = zfs_open(zlibh, nlp->nlp_clonename,
 246             ZFS_TYPE_VOLUME | ZFS_TYPE_FILESYSTEM)) == NULL) {
 247                 syslog(LOG_ERR,
 248                     "backup_dataset_destroy: open %s failed",
 249                     nlp->nlp_clonename);
 250                 (void) mutex_unlock(&zlib_mtx);
 251                 return (-1);
 252         }
 253 
 254         /*
 255          * Open the mounted clone to get descriptor for unmount
 256          */
 257         if ((vol_zhp = zfs_open(zlibh, nlp->nlp_vol,
 258             ZFS_TYPE_VOLUME | ZFS_TYPE_FILESYSTEM)) == NULL) {
 259                 syslog(LOG_ERR,
 260                     "backup_dataset_destroy: open %s failed [while trying "
 261                     "to destroy]", nlp->nlp_vol);
 262                 zfs_close(cln_zhp);
 263                 (void) mutex_unlock(&zlib_mtx);
 264                 return (-1);
 265         }
 266 
 267         /*
 268          * This unmounts the clone which was just traversed for backup
 269          */
 270         if ((err = zfs_unmount(cln_zhp, NULL, 0)) != 0) {
 271                 syslog(LOG_INFO, "failed to unmount [%s]", nlp->nlp_clonename);
 272                 rv = -1;
 273                 goto _out;
 274         }
 275 
 276         /*
 277          * This destroys the clone
 278          */
 279         err = zfs_destroy(cln_zhp, B_TRUE);
 280         if (err) {
 281                 syslog(LOG_ERR, "%s destroy: %d; %s; %s",
 282                     nlp->nlp_clonename,

 283                     libzfs_errno(zlibh),
 284                     libzfs_error_action(zlibh),
 285                     libzfs_error_description(zlibh));
 286                 rv = -1;
 287                 goto _out;
 288         }
 289 
 290         /*
 291          * This destroys the snapshot of the current backup - but,
 292          * don't destroy it if it is an "checkpoint" from AutoSync
 293          * or HPR.
 294          */
 295         if (!NLP_ISCHKPNTED(nlp)) {
 296                 if ((err = zfs_destroy_snaps(vol_zhp,
 297                     nlp->nlp_job_name, B_TRUE))) {
 298                         syslog(LOG_ERR, "%s destroy: %d; %s; %s",
 299                             nlp->nlp_job_name,
 300                             libzfs_errno(zlibh),
 301                             libzfs_error_action(zlibh),
 302                             libzfs_error_description(zlibh));
 303                         rv = -1;
 304                         syslog(LOG_DEBUG, "Destroy [%s]", nlp->nlp_snapname);
 305                         goto _out;
 306                 }
 307         } else {
 308                 syslog(LOG_DEBUG, "Checkpointed checkpoint will not destroy [%s]",
 309                     nlp->nlp_snapname);
 310         }
 311 
 312 _out:
 313         zfs_close(vol_zhp);
 314         zfs_close(cln_zhp);
 315         (void) mutex_unlock(&zlib_mtx);
 316 
 317         /*
 318          * The zfs_clone() call will have mounted the snapshot
 319          * in the file system at this point - so clean it up.
 320          */
 321         if (rv == 0) {
 322                 if (rmdir(nlp->nlp_mountpoint) != 0) {
 323                         syslog(LOG_ERR,
 324                             "Failed to remove mount point [%s]",
 325                             nlp->nlp_mountpoint);
 326                         return (-1);
 327                 }
 328         }
 329 
 330         return (rv);
 331 }