1 /*
2 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
3 * Copyright (c) 2013 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
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
101 ndmp_has_backup_snapshot(char *volname, char *jobname)
102 {
103 zfs_handle_t *zhp;
104 snap_param_t snp;
105 char chname[ZFS_MAXNAMELEN];
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_MAXNAMELEN, "@%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
140 ndmp_create_snapshot(char *vol_name, char *jname)
141 {
142 char vol[ZFS_MAXNAMELEN];
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
174 ndmp_remove_snapshot(char *vol_name, char *jname)
175 {
176 char vol[ZFS_MAXNAMELEN];
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
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
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
246 snapshot_create(char *volname, char *jname, boolean_t recursive,
247 boolean_t hold)
248 {
249 char snapname[ZFS_MAXNAMELEN];
250 int rv;
251
252 if (!volname || !*volname)
253 return (-1);
254
255 (void) snprintf(snapname, ZFS_MAXNAMELEN, "%s@%s", volname, jname);
256
257 (void) mutex_lock(&zlib_mtx);
258 if ((rv = zfs_snapshot(zlibh, snapname, recursive, NULL))
259 == -1) {
260 if (errno == EEXIST) {
261 (void) mutex_unlock(&zlib_mtx);
262 return (0);
263 }
264 NDMP_LOG(LOG_DEBUG,
265 "snapshot_create: %s failed (err=%d): %s",
266 snapname, errno, libzfs_error_description(zlibh));
267 (void) mutex_unlock(&zlib_mtx);
268 return (rv);
269 }
270 if (hold && snapshot_hold(volname, snapname, jname, recursive) != 0) {
271 NDMP_LOG(LOG_DEBUG,
272 "snapshot_create: %s hold failed (err=%d): %s",
273 snapname, errno, libzfs_error_description(zlibh));
274 (void) mutex_unlock(&zlib_mtx);
275 return (-1);
276 }
277
278 (void) mutex_unlock(&zlib_mtx);
279 return (0);
280 }
281
282 /*
283 * Remove and release the backup snapshot
284 */
285 int
286 snapshot_destroy(char *volname, char *jname, boolean_t recursive,
287 boolean_t hold, int *zfs_err)
288 {
289 char snapname[ZFS_MAXNAMELEN];
290 zfs_handle_t *zhp;
291 zfs_type_t ztype;
292 char *namep;
293 int err;
294
295 if (zfs_err)
296 *zfs_err = 0;
297
298 if (!volname || !*volname)
299 return (-1);
300
301 if (recursive) {
302 ztype = ZFS_TYPE_VOLUME | ZFS_TYPE_FILESYSTEM;
303 namep = volname;
304 } else {
305 (void) snprintf(snapname, ZFS_MAXNAMELEN, "%s@%s", volname,
306 jname);
307 namep = snapname;
308 ztype = ZFS_TYPE_SNAPSHOT;
309 }
310
311 (void) mutex_lock(&zlib_mtx);
312 if (hold &&
313 snapshot_release(volname, namep, jname, recursive) != 0) {
314 NDMP_LOG(LOG_DEBUG,
315 "snapshot_destroy: %s release failed (err=%d): %s",
316 namep, errno, libzfs_error_description(zlibh));
317 (void) mutex_unlock(&zlib_mtx);
318 return (-1);
319 }
320
321 if ((zhp = zfs_open(zlibh, namep, ztype)) == NULL) {
322 NDMP_LOG(LOG_DEBUG, "snapshot_destroy: open %s failed",
323 namep);
324 (void) mutex_unlock(&zlib_mtx);
325 return (-1);
326 }
327
328 if (recursive) {
329 err = zfs_destroy_snaps(zhp, jname, B_TRUE);
330 } else {
331 err = zfs_destroy(zhp, B_TRUE);
332 }
333
334 if (err) {
335 NDMP_LOG(LOG_ERR, "%s (recursive destroy: %d): %d; %s; %s",
336 namep,
337 recursive,
338 libzfs_errno(zlibh),
339 libzfs_error_action(zlibh),
340 libzfs_error_description(zlibh));
341
342 if (zfs_err)
343 *zfs_err = err;
344 }
345
346 zfs_close(zhp);
347 (void) mutex_unlock(&zlib_mtx);
348
349 return (0);
350 }