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 typedef struct snap_param {
45 char *snp_name;
46 boolean_t snp_found;
47 } snap_param_t;
48
49 static int cleanup_fd = -1;
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
ndmp_has_backup(zfs_handle_t * zhp,void * data)67 ndmp_has_backup(zfs_handle_t *zhp, void *data)
68 {
69 const char *name;
70 snap_param_t *chp = (snap_param_t *)data;
71
72 name = zfs_get_name(zhp);
73 if (name == NULL ||
74 strstr(name, chp->snp_name) == NULL) {
75 zfs_close(zhp);
76 return (-1);
77 }
78
79 chp->snp_found = 1;
80 zfs_close(zhp);
81
82 return (0);
83 }
84
85 /*
86 * ndmp_has_backup_snapshot
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
ndmp_has_backup_snapshot(char * volname,char * jobname)99 ndmp_has_backup_snapshot(char *volname, char *jobname)
100 {
101 zfs_handle_t *zhp;
102 snap_param_t snp;
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 snapshot %s.", volname);
108 (void) mutex_unlock(&zlib_mtx);
109 return (-1);
110 }
111
112 snp.snp_found = 0;
113 (void) snprintf(chname, ZFS_MAXNAMELEN, "@%s", jobname);
114 snp.snp_name = chname;
115
116 (void) zfs_iter_snapshots(zhp, ndmp_has_backup, &snp);
117 zfs_close(zhp);
118 (void) mutex_unlock(&zlib_mtx);
119
120 return (snp.snp_found);
121 }
122
123 /*
124 * ndmp_create_snapshot
125 *
126 * This function will parse the path to get the real volume name.
127 * It will then create a snapshot based on volume and job name.
128 * This function should be called before the NDMP backup is started.
129 *
130 * Parameters:
131 * vol_name (input) - name of the volume
132 *
133 * Returns:
134 * 0: on success
135 * -1: otherwise
136 */
137 int
ndmp_create_snapshot(char * vol_name,char * jname)138 ndmp_create_snapshot(char *vol_name, char *jname)
139 {
140 char vol[ZFS_MAXNAMELEN];
141
142 if (vol_name == 0 ||
143 get_zfsvolname(vol, sizeof (vol), vol_name) == -1)
144 return (0);
145
146 /*
147 * If there is an old snapshot left from the previous
148 * backup it could be stale one and it must be
149 * removed before using it.
150 */
151 if (ndmp_has_backup_snapshot(vol, jname))
152 (void) snapshot_destroy(vol, jname, B_FALSE, B_TRUE, NULL);
153
154 return (snapshot_create(vol, jname, B_FALSE, B_TRUE));
155 }
156
157 /*
158 * ndmp_remove_snapshot
159 *
160 * This function will parse the path to get the real volume name.
161 * It will then remove the snapshot for that volume and job name.
162 * This function should be called after NDMP backup is finished.
163 *
164 * Parameters:
165 * vol_name (input) - name of the volume
166 *
167 * Returns:
168 * 0: on success
169 * -1: otherwise
170 */
171 int
ndmp_remove_snapshot(char * vol_name,char * jname)172 ndmp_remove_snapshot(char *vol_name, char *jname)
173 {
174 char vol[ZFS_MAXNAMELEN];
175
176 if (vol_name == 0 ||
177 get_zfsvolname(vol, sizeof (vol), vol_name) == -1)
178 return (0);
179
180 return (snapshot_destroy(vol, jname, B_FALSE, B_TRUE, NULL));
181 }
182
183 /*
184 * Put a hold on snapshot
185 */
186 int
snapshot_hold(char * volname,char * snapname,char * jname,boolean_t recursive)187 snapshot_hold(char *volname, char *snapname, char *jname, boolean_t recursive)
188 {
189 zfs_handle_t *zhp;
190 char *p;
191
192 if ((zhp = zfs_open(zlibh, volname, ZFS_TYPE_DATASET)) == 0) {
193 NDMP_LOG(LOG_ERR, "Cannot open volume %s.", volname);
194 return (-1);
195 }
196
197 if (cleanup_fd == -1 && (cleanup_fd = open(ZFS_DEV,
198 O_RDWR|O_EXCL)) < 0) {
199 NDMP_LOG(LOG_ERR, "Cannot open dev %d", errno);
200 zfs_close(zhp);
201 return (-1);
202 }
203
204 p = strchr(snapname, '@') + 1;
205 if (zfs_hold(zhp, p, jname, recursive, B_TRUE, B_FALSE,
206 cleanup_fd, 0, 0) != 0) {
207 NDMP_LOG(LOG_ERR, "Cannot hold snapshot %s", p);
208 zfs_close(zhp);
209 return (-1);
210 }
211 zfs_close(zhp);
212 return (0);
213 }
214
215 int
snapshot_release(char * volname,char * snapname,char * jname,boolean_t recursive)216 snapshot_release(char *volname, char *snapname, char *jname,
217 boolean_t recursive)
218 {
219 zfs_handle_t *zhp;
220 char *p;
221 int rv = 0;
222
223 if ((zhp = zfs_open(zlibh, volname, ZFS_TYPE_DATASET)) == 0) {
224 NDMP_LOG(LOG_ERR, "Cannot open volume %s", volname);
225 return (-1);
226 }
227
228 p = strchr(snapname, '@') + 1;
229 if (zfs_release(zhp, p, jname, recursive) != 0) {
230 NDMP_LOG(LOG_DEBUG, "Cannot release snapshot %s", p);
231 rv = -1;
232 }
233 if (cleanup_fd != -1) {
234 (void) close(cleanup_fd);
235 cleanup_fd = -1;
236 }
237 zfs_close(zhp);
238 return (rv);
239 }
240
241 /*
242 * Create a snapshot on the volume
243 */
244 int
snapshot_create(char * volname,char * jname,boolean_t recursive,boolean_t hold)245 snapshot_create(char *volname, char *jname, boolean_t recursive,
246 boolean_t hold)
247 {
248 char snapname[ZFS_MAXNAMELEN];
249 int rv;
250
251 if (!volname || !*volname)
252 return (-1);
253
254 (void) snprintf(snapname, ZFS_MAXNAMELEN, "%s@%s", volname, jname);
255
256 (void) mutex_lock(&zlib_mtx);
257 if ((rv = zfs_snapshot(zlibh, snapname, recursive, NULL))
258 == -1) {
259 if (errno == EEXIST) {
260 (void) mutex_unlock(&zlib_mtx);
261 return (0);
262 }
263 NDMP_LOG(LOG_DEBUG,
264 "snapshot_create: %s failed (err=%d): %s",
265 snapname, errno, libzfs_error_description(zlibh));
266 (void) mutex_unlock(&zlib_mtx);
267 return (rv);
268 }
269 if (hold && snapshot_hold(volname, snapname, jname, recursive) != 0) {
270 NDMP_LOG(LOG_DEBUG,
271 "snapshot_create: %s hold failed (err=%d): %s",
272 snapname, errno, libzfs_error_description(zlibh));
273 (void) mutex_unlock(&zlib_mtx);
274 return (-1);
275 }
276
277 (void) mutex_unlock(&zlib_mtx);
278 return (0);
279 }
280
281 /*
282 * Remove and release the backup snapshot
283 */
284 int
snapshot_destroy(char * volname,char * jname,boolean_t recursive,boolean_t hold,int * zfs_err)285 snapshot_destroy(char *volname, char *jname, boolean_t recursive,
286 boolean_t hold, int *zfs_err)
287 {
288 char snapname[ZFS_MAXNAMELEN];
289 zfs_handle_t *zhp;
290 zfs_type_t ztype;
291 char *namep;
292 int err;
293
294 if (zfs_err)
295 *zfs_err = 0;
296
297 if (!volname || !*volname)
298 return (-1);
299
300 if (recursive) {
301 ztype = ZFS_TYPE_VOLUME | ZFS_TYPE_FILESYSTEM;
302 namep = volname;
303 } else {
304 (void) snprintf(snapname, ZFS_MAXNAMELEN, "%s@%s", volname,
305 jname);
306 namep = snapname;
307 ztype = ZFS_TYPE_SNAPSHOT;
308 }
309
310 (void) mutex_lock(&zlib_mtx);
311 if (hold &&
312 snapshot_release(volname, namep, jname, recursive) != 0) {
313 NDMP_LOG(LOG_DEBUG,
314 "snapshot_destroy: %s release failed (err=%d): %s",
315 namep, errno, libzfs_error_description(zlibh));
316 (void) mutex_unlock(&zlib_mtx);
317 return (-1);
318 }
319
320 if ((zhp = zfs_open(zlibh, namep, ztype)) == NULL) {
321 NDMP_LOG(LOG_DEBUG, "snapshot_destroy: open %s failed",
322 namep);
323 (void) mutex_unlock(&zlib_mtx);
324 return (-1);
325 }
326
327 if (recursive) {
328 err = zfs_destroy_snaps(zhp, jname, B_TRUE);
329 } else {
330 err = zfs_destroy(zhp, B_TRUE);
331 }
332
333 if (err) {
334 NDMP_LOG(LOG_ERR, "%s (recursive destroy: %d): %d; %s; %s",
335 namep,
336 recursive,
337 libzfs_errno(zlibh),
338 libzfs_error_action(zlibh),
339 libzfs_error_description(zlibh));
340
341 if (zfs_err)
342 *zfs_err = err;
343 }
344
345 zfs_close(zhp);
346 (void) mutex_unlock(&zlib_mtx);
347
348 return (0);
349 }
350