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