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 }