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 */ 6 7 /* 8 * BSD 3 Clause License 9 * 10 * Copyright (c) 2007, The Storage Networking Industry Association. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * - Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 18 * - Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in 20 * the documentation and/or other materials provided with the 21 * distribution. 22 * 23 * - Neither the name of The Storage Networking Industry Association (SNIA) 24 * nor the names of its contributors may be used to endorse or promote 25 * products derived from this software without specific prior written 26 * permission. 27 * 28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 29 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 31 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 32 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 33 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 34 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 35 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 36 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 37 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 38 * POSSIBILITY OF SUCH DAMAGE. 39 */ 40 41 #include <stdio.h> 42 #include <string.h> 43 #include "ndmpd.h" 44 #include <libzfs.h> 45 46 typedef struct snap_param { 47 char *snp_name; 48 boolean_t snp_found; 49 } snap_param_t; 50 51 static int cleanup_fd = -1; 52 53 /* 54 * ndmp_has_backup 55 * 56 * Call backup function which looks for backup snapshot. 57 * This is a callback function used with zfs_iter_snapshots. 58 * 59 * Parameters: 60 * zhp (input) - ZFS handle pointer 61 * data (output) - 0 - no backup snapshot 62 * 1 - has backup snapshot 63 * 64 * Returns: 65 * 0: on success 66 * -1: otherwise 67 */ 68 static int 69 ndmp_has_backup(zfs_handle_t *zhp, void *data) 70 { 71 const char *name; 72 snap_param_t *chp = (snap_param_t *)data; 73 74 name = zfs_get_name(zhp); 75 if (name == NULL || 76 strstr(name, chp->snp_name) == NULL) { 77 zfs_close(zhp); 78 return (-1); 79 } 80 81 chp->snp_found = 1; 82 zfs_close(zhp); 83 84 return (0); 85 } 86 87 /* 88 * ndmp_has_backup_snapshot 89 * 90 * Returns TRUE if the volume has an active backup snapshot, otherwise, 91 * returns FALSE. 92 * 93 * Parameters: 94 * volname (input) - name of the volume 95 * 96 * Returns: 97 * 0: on success 98 * -1: otherwise 99 */ 100 static int 101 ndmp_has_backup_snapshot(char *volname, char *jobname) 102 { 103 zfs_handle_t *zhp; 104 snap_param_t snp; 105 char chname[ZFS_MAX_DATASET_NAME_LEN]; 106 107 (void) mutex_lock(&zlib_mtx); 108 if ((zhp = zfs_open(zlibh, volname, ZFS_TYPE_DATASET)) == 0) { 109 NDMP_LOG(LOG_ERR, "Cannot open snapshot %s.", volname); 110 (void) mutex_unlock(&zlib_mtx); 111 return (-1); 112 } 113 114 snp.snp_found = 0; 115 (void) snprintf(chname, ZFS_MAX_DATASET_NAME_LEN, "@%s", jobname); 116 snp.snp_name = chname; 117 118 (void) zfs_iter_snapshots(zhp, ndmp_has_backup, &snp); 119 zfs_close(zhp); 120 (void) mutex_unlock(&zlib_mtx); 121 122 return (snp.snp_found); 123 } 124 125 /* 126 * ndmp_create_snapshot 127 * 128 * This function will parse the path to get the real volume name. 129 * It will then create a snapshot based on volume and job name. 130 * This function should be called before the NDMP backup is started. 131 * 132 * Parameters: 133 * vol_name (input) - name of the volume 134 * 135 * Returns: 136 * 0: on success 137 * -1: otherwise 138 */ 139 int 140 ndmp_create_snapshot(char *vol_name, char *jname) 141 { 142 char vol[ZFS_MAX_DATASET_NAME_LEN]; 143 144 if (vol_name == 0 || 145 get_zfsvolname(vol, sizeof (vol), vol_name) == -1) 146 return (0); 147 148 /* 149 * If there is an old snapshot left from the previous 150 * backup it could be stale one and it must be 151 * removed before using it. 152 */ 153 if (ndmp_has_backup_snapshot(vol, jname)) 154 (void) snapshot_destroy(vol, jname, B_FALSE, B_TRUE, NULL); 155 156 return (snapshot_create(vol, jname, B_FALSE, B_TRUE)); 157 } 158 159 /* 160 * ndmp_remove_snapshot 161 * 162 * This function will parse the path to get the real volume name. 163 * It will then remove the snapshot for that volume and job name. 164 * This function should be called after NDMP backup is finished. 165 * 166 * Parameters: 167 * vol_name (input) - name of the volume 168 * 169 * Returns: 170 * 0: on success 171 * -1: otherwise 172 */ 173 int 174 ndmp_remove_snapshot(char *vol_name, char *jname) 175 { 176 char vol[ZFS_MAX_DATASET_NAME_LEN]; 177 178 if (vol_name == 0 || 179 get_zfsvolname(vol, sizeof (vol), vol_name) == -1) 180 return (0); 181 182 return (snapshot_destroy(vol, jname, B_FALSE, B_TRUE, NULL)); 183 } 184 185 /* 186 * Put a hold on snapshot 187 */ 188 int 189 snapshot_hold(char *volname, char *snapname, char *jname, boolean_t recursive) 190 { 191 zfs_handle_t *zhp; 192 char *p; 193 194 if ((zhp = zfs_open(zlibh, volname, ZFS_TYPE_DATASET)) == 0) { 195 NDMP_LOG(LOG_ERR, "Cannot open volume %s.", volname); 196 return (-1); 197 } 198 199 if (cleanup_fd == -1 && (cleanup_fd = open(ZFS_DEV, 200 O_RDWR|O_EXCL)) < 0) { 201 NDMP_LOG(LOG_ERR, "Cannot open dev %d", errno); 202 zfs_close(zhp); 203 return (-1); 204 } 205 206 p = strchr(snapname, '@') + 1; 207 if (zfs_hold(zhp, p, jname, recursive, cleanup_fd) != 0) { 208 NDMP_LOG(LOG_ERR, "Cannot hold snapshot %s", p); 209 zfs_close(zhp); 210 return (-1); 211 } 212 zfs_close(zhp); 213 return (0); 214 } 215 216 int 217 snapshot_release(char *volname, char *snapname, char *jname, 218 boolean_t recursive) 219 { 220 zfs_handle_t *zhp; 221 char *p; 222 int rv = 0; 223 224 if ((zhp = zfs_open(zlibh, volname, ZFS_TYPE_DATASET)) == 0) { 225 NDMP_LOG(LOG_ERR, "Cannot open volume %s", volname); 226 return (-1); 227 } 228 229 p = strchr(snapname, '@') + 1; 230 if (zfs_release(zhp, p, jname, recursive) != 0) { 231 NDMP_LOG(LOG_DEBUG, "Cannot release snapshot %s", p); 232 rv = -1; 233 } 234 if (cleanup_fd != -1) { 235 (void) close(cleanup_fd); 236 cleanup_fd = -1; 237 } 238 zfs_close(zhp); 239 return (rv); 240 } 241 242 /* 243 * Create a snapshot on the volume 244 */ 245 int 246 snapshot_create(char *volname, char *jname, boolean_t recursive, 247 boolean_t hold) 248 { 249 char snapname[ZFS_MAX_DATASET_NAME_LEN]; 250 int rv; 251 252 if (!volname || !*volname) 253 return (-1); 254 255 (void) snprintf(snapname, ZFS_MAX_DATASET_NAME_LEN, 256 "%s@%s", volname, jname); 257 258 (void) mutex_lock(&zlib_mtx); 259 if ((rv = zfs_snapshot(zlibh, snapname, recursive, NULL)) 260 == -1) { 261 if (errno == EEXIST) { 262 (void) mutex_unlock(&zlib_mtx); 263 return (0); 264 } 265 NDMP_LOG(LOG_DEBUG, 266 "snapshot_create: %s failed (err=%d): %s", 267 snapname, errno, libzfs_error_description(zlibh)); 268 (void) mutex_unlock(&zlib_mtx); 269 return (rv); 270 } 271 if (hold && snapshot_hold(volname, snapname, jname, recursive) != 0) { 272 NDMP_LOG(LOG_DEBUG, 273 "snapshot_create: %s hold failed (err=%d): %s", 274 snapname, errno, libzfs_error_description(zlibh)); 275 (void) mutex_unlock(&zlib_mtx); 276 return (-1); 277 } 278 279 (void) mutex_unlock(&zlib_mtx); 280 return (0); 281 } 282 283 /* 284 * Remove and release the backup snapshot 285 */ 286 int 287 snapshot_destroy(char *volname, char *jname, boolean_t recursive, 288 boolean_t hold, int *zfs_err) 289 { 290 char snapname[ZFS_MAX_DATASET_NAME_LEN]; 291 zfs_handle_t *zhp; 292 zfs_type_t ztype; 293 char *namep; 294 int err; 295 296 if (zfs_err) 297 *zfs_err = 0; 298 299 if (!volname || !*volname) 300 return (-1); 301 302 if (recursive) { 303 ztype = ZFS_TYPE_VOLUME | ZFS_TYPE_FILESYSTEM; 304 namep = volname; 305 } else { 306 (void) snprintf(snapname, ZFS_MAX_DATASET_NAME_LEN, 307 "%s@%s", volname, jname); 308 namep = snapname; 309 ztype = ZFS_TYPE_SNAPSHOT; 310 } 311 312 (void) mutex_lock(&zlib_mtx); 313 if (hold && 314 snapshot_release(volname, namep, jname, recursive) != 0) { 315 NDMP_LOG(LOG_DEBUG, 316 "snapshot_destroy: %s release failed (err=%d): %s", 317 namep, errno, libzfs_error_description(zlibh)); 318 (void) mutex_unlock(&zlib_mtx); 319 return (-1); 320 } 321 322 if ((zhp = zfs_open(zlibh, namep, ztype)) == NULL) { 323 NDMP_LOG(LOG_DEBUG, "snapshot_destroy: open %s failed", 324 namep); 325 (void) mutex_unlock(&zlib_mtx); 326 return (-1); 327 } 328 329 if (recursive) { 330 err = zfs_destroy_snaps(zhp, jname, B_TRUE); 331 } else { 332 err = zfs_destroy(zhp, B_TRUE); 333 } 334 335 if (err) { 336 NDMP_LOG(LOG_ERR, "%s (recursive destroy: %d): %d; %s; %s", 337 namep, 338 recursive, 339 libzfs_errno(zlibh), 340 libzfs_error_action(zlibh), 341 libzfs_error_description(zlibh)); 342 343 if (zfs_err) 344 *zfs_err = err; 345 } 346 347 zfs_close(zhp); 348 (void) mutex_unlock(&zlib_mtx); 349 350 return (0); 351 } 352