1 /* 2 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. 3 * Copyright (c) 2013 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_MAXNAMELEN]; 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_MAXNAMELEN, "@%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_MAXNAMELEN]; 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_MAXNAMELEN]; 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_MAXNAMELEN]; 251 int rv; 252 253 if (!volname || !*volname) 254 return (-1); 255 256 (void) snprintf(snapname, ZFS_MAXNAMELEN, "%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_MAXNAMELEN]; 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_MAXNAMELEN, "%s@%s", volname, 307 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