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