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