Home | History | Annotate | Download | only in ndmp
      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