1 /* 2 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 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 ndmp_chkpnt_vol_t *chkpnt_vols = NULL; 46 47 typedef struct chkpnt_param { 48 char *chp_name; 49 boolean_t chp_found; 50 } chkpnt_param_t; 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 chkpnt_param_t *chp = (chkpnt_param_t *)data; 72 73 name = zfs_get_name(zhp); 74 if (name == NULL || 75 strstr(name, chp->chp_name) == NULL) { 76 zfs_close(zhp); 77 return (-1); 78 } 79 80 chp->chp_found = 1; 81 zfs_close(zhp); 82 83 return (0); 84 } 85 86 /* 87 * ndmp_has_backup_chkpnt 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_chkpnt(char *volname, char *jobname) 101 { 102 zfs_handle_t *zhp; 103 chkpnt_param_t chkp; 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 checkpoint %s.", volname); 109 (void) mutex_unlock(&zlib_mtx); 110 return (-1); 111 } 112 113 chkp.chp_found = 0; 114 (void) snprintf(chname, ZFS_MAXNAMELEN, "@bk-%s", jobname); 115 chkp.chp_name = chname; 116 117 (void) zfs_iter_snapshots(zhp, ndmp_has_backup, &chkp); 118 zfs_close(zhp); 119 (void) mutex_unlock(&zlib_mtx); 120 121 return (chkp.chp_found); 122 } 123 124 125 /* 126 * ndmp_add_chk_pnt_vol 127 * 128 * This function keep track of check points created by NDMP. Whenever the 129 * NDMP check points need to be created, this function should be called. 130 * If the value returned is bigger than 1, it indicates that the check point 131 * has already exists and should not be created. 132 * 133 * Parameters: 134 * vol_name (input) - name of the volume 135 * 136 * Returns: 137 * The number of existing snapshots 138 */ 139 static unsigned int 140 ndmp_add_chk_pnt_vol(char *vol_name) 141 { 142 ndmp_chkpnt_vol_t *new_chkpnt_vol; 143 144 for (new_chkpnt_vol = chkpnt_vols; new_chkpnt_vol != NULL; 145 new_chkpnt_vol = new_chkpnt_vol->cv_next) { 146 if (strcmp(new_chkpnt_vol->cv_vol_name, vol_name) == 0) { 147 new_chkpnt_vol->cv_count++; 148 return (new_chkpnt_vol->cv_count); 149 } 150 } 151 152 new_chkpnt_vol = ndmp_malloc(sizeof (ndmp_chkpnt_vol_t)); 153 if (new_chkpnt_vol == NULL) 154 return (0); 155 156 (void) memset(new_chkpnt_vol, 0, sizeof (ndmp_chkpnt_vol_t)); 157 (void) strlcpy(new_chkpnt_vol->cv_vol_name, vol_name, 158 sizeof (new_chkpnt_vol->cv_vol_name)); 159 160 new_chkpnt_vol->cv_count++; 161 162 if (chkpnt_vols == NULL) { 163 chkpnt_vols = new_chkpnt_vol; 164 } else { 165 new_chkpnt_vol->cv_next = chkpnt_vols; 166 chkpnt_vols = new_chkpnt_vol; 167 } 168 169 return (new_chkpnt_vol->cv_count); 170 } 171 172 173 /* 174 * ndmp_remove_chk_pnt_vol 175 * 176 * This function will decrement the usage counter belongs to the check point. 177 * Whenever a check point needs to be removed, this function should be 178 * called. When the return value is greater than zero, it indicates someone 179 * else is still using the check point and the check point should not be 180 * removed. 181 * 182 * Parameters: 183 * vol_name (input) - name of the volume 184 * 185 * Returns: 186 * The number of existing snapshots 187 */ 188 static unsigned int 189 ndmp_remove_chk_pnt_vol(char *vol_name) 190 { 191 ndmp_chkpnt_vol_t *new_chkpnt_vol, *pre_chkpnt_vol; 192 193 pre_chkpnt_vol = chkpnt_vols; 194 for (new_chkpnt_vol = chkpnt_vols; new_chkpnt_vol != NULL; 195 new_chkpnt_vol = new_chkpnt_vol->cv_next) { 196 if (strcmp(new_chkpnt_vol->cv_vol_name, vol_name) == 0) { 197 new_chkpnt_vol->cv_count--; 198 199 if (new_chkpnt_vol->cv_count == 0) { 200 if (pre_chkpnt_vol == new_chkpnt_vol && 201 new_chkpnt_vol->cv_next == NULL) 202 chkpnt_vols = NULL; 203 else if (pre_chkpnt_vol == new_chkpnt_vol) 204 chkpnt_vols = new_chkpnt_vol->cv_next; 205 else 206 pre_chkpnt_vol->cv_next = 207 new_chkpnt_vol->cv_next; 208 209 free(new_chkpnt_vol); 210 return (0); 211 } 212 return (new_chkpnt_vol->cv_count); 213 } 214 if (new_chkpnt_vol != chkpnt_vols) 215 pre_chkpnt_vol = pre_chkpnt_vol->cv_next; 216 } 217 218 return (0); 219 } 220 221 222 223 224 /* 225 * ndmp_start_check_point 226 * 227 * This function will parse the path, vol_name, to get the real volume name. 228 * It will then check via ndmp_add_chk_pnt_vol to see if creating a check point 229 * for the volume is necessary. If it is, a checkpoint is created. 230 * This function should be called before the NDMP backup is started. 231 * 232 * Parameters: 233 * vol_name (input) - name of the volume 234 * 235 * Returns: 236 * 0: on success 237 * -1: otherwise 238 */ 239 int 240 ndmp_start_check_point(char *vol_name, char *jname) 241 { 242 int erc = 0; 243 char vol[ZFS_MAXNAMELEN]; 244 245 if (vol_name == 0 || 246 get_zfsvolname(vol, sizeof (vol), vol_name) == -1) 247 return (0); 248 249 if (ndmp_add_chk_pnt_vol(vol) > 0) { 250 /* 251 * If there is an old checkpoint left from the previous 252 * backup and the reference count of backup checkpoint of 253 * the volume is 1 after increasing it, it shows that the 254 * checkpoint on file system is a stale one and it must be 255 * removed before using it. 256 */ 257 if (ndmp_has_backup_chkpnt(vol, jname)) 258 (void) chkpnt_backup_successful(vol, jname); 259 if ((erc = chkpnt_backup_prepare(vol, jname)) < 0) 260 (void) ndmp_remove_chk_pnt_vol(vol); 261 } 262 263 return (erc); 264 } 265 266 /* 267 * ndmp_release_check_point 268 * 269 * This function will parse the path, vol_name, to get the real volume name. 270 * It will then check via ndmp_remove_chk_pnt_vol to see if removing a check 271 * point for the volume is necessary. If it is, a checkpoint is removed. 272 * This function should be called after NDMP backup is finished. 273 * 274 * Parameters: 275 * vol_name (input) - name of the volume 276 * 277 * Returns: 278 * 0: on success 279 * -1: otherwise 280 */ 281 int 282 ndmp_release_check_point(char *vol_name, char *jname) 283 { 284 int erc = 0; 285 char vol[ZFS_MAXNAMELEN]; 286 287 if (vol_name == 0 || 288 get_zfsvolname(vol, sizeof (vol), vol_name)) 289 return (0); 290 291 if (ndmp_remove_chk_pnt_vol(vol) == 0) 292 erc = chkpnt_backup_successful(vol, jname); 293 294 return (erc); 295 } 296