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