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 } 353