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 * Copyright (c) 2016 Martin Matuska. All rights reserved.
6 * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
7 */
8
9 /*
10 * BSD 3 Clause License
11 *
12 * Copyright (c) 2007, The Storage Networking Industry Association.
13 *
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions
16 * are met:
17 * - Redistributions of source code must retain the above copyright
18 * notice, this list of conditions and the following disclaimer.
19 *
20 * - Redistributions in binary form must reproduce the above copyright
21 * notice, this list of conditions and the following disclaimer in
22 * the documentation and/or other materials provided with the
23 * distribution.
24 *
25 * - Neither the name of The Storage Networking Industry Association (SNIA)
26 * nor the names of its contributors may be used to endorse or promote
27 * products derived from this software without specific prior written
28 * permission.
29 *
30 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
31 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
32 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
34 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
35 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
36 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
37 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
38 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
39 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
40 * POSSIBILITY OF SUCH DAMAGE.
41 */
42
43 #include <syslog.h>
44 #include <stdio.h>
45 #include <string.h>
46 #include <sys/mount.h>
47 #include "ndmpd.h"
48 #include <libzfs.h>
49
50 /*
51 * Put a hold on snapshot
52 */
53 int
54 snapshot_hold(char *volname, char *snapname, char *jname)
55 {
56 zfs_handle_t *zhp;
57 char *p;
58
59 if ((zhp = zfs_open(zlibh, volname, ZFS_TYPE_DATASET)) == 0) {
60 syslog(LOG_ERR, "Cannot open volume %s.", volname);
61 return (-1);
62 }
63 p = strchr(snapname, '@') + 1;
64 /*
65 * The -1 tells the lower levels there are no snapshots
66 * to clean up.
67 */
68 if (zfs_hold(zhp, p, jname, B_FALSE, -1) != 0) {
69 syslog(LOG_ERR, "Cannot hold snapshot %s", p);
70 zfs_close(zhp);
71 return (-1);
72 }
73 zfs_close(zhp);
74 return (0);
75 }
76
77 int
78 snapshot_release(char *volname, char *snapname, char *jname)
79 {
80 zfs_handle_t *zhp;
81 char *p;
82 int rv = 0;
83
84 if ((zhp = zfs_open(zlibh, volname, ZFS_TYPE_DATASET)) == 0) {
85 syslog(LOG_ERR, "Cannot open volume %s", volname);
86 return (-1);
87 }
88
89 p = strchr(snapname, '@') + 1;
90 if (zfs_release(zhp, p, jname, B_FALSE) != 0) {
91 syslog(LOG_DEBUG, "Cannot release snapshot %s", p);
92 rv = -1;
93 }
94 zfs_close(zhp);
95 return (rv);
96 }
97
98 /*
99 * Create a snapshot, put a hold on it, clone it, and mount it in a
100 * well known location for so the backup process can traverse its
101 * directory tree structure.
102 */
103 int
104 backup_dataset_create(ndmp_lbr_params_t *nlp)
105 {
106 char zpoolname[ZFS_MAX_DATASET_NAME_LEN];
107 char *slash;
108 int rv;
109
110 if (nlp == NULL) {
111 return (-1);
112 }
113
114 (void) strlcpy(zpoolname, nlp->nlp_vol, sizeof (zpoolname));
115 /*
116 * Pull out the pool name component from the volname
117 * to use it to build snapshot and clone names.
118 */
119 slash = strchr(zpoolname, '/');
120 if (slash != NULL) {
121 *slash = '\0';
122 }
123
124 (void) snprintf(nlp->nlp_clonename, sizeof (nlp->nlp_clonename),
125 "%s/%s", zpoolname, nlp->nlp_job_name);
126
127 (void) mutex_lock(&zlib_mtx);
128
129 /*
130 * If "checkpoint" is not enabled, create the normal
131 * snapshot and continue normal backup. If it is
132 * enabled, the "checkpoint" name has been already set
133 * so we just have to clone it.
134 */
135 if (!NLP_ISCHKPNTED(nlp)) {
136 (void) snprintf(nlp->nlp_snapname, sizeof (nlp->nlp_snapname),
137 "%s@%s", nlp->nlp_vol, nlp->nlp_job_name);
138
139 if ((rv = zfs_snapshot(zlibh, nlp->nlp_snapname,
140 B_FALSE, NULL)) != 0) {
141 if (errno == EEXIST) {
142 (void) mutex_unlock(&zlib_mtx);
143 return (0);
144 }
145 syslog(LOG_ERR,
146 "backup_dataset_create: %s failed (err=%d): %s",
147 nlp->nlp_snapname, errno,
148 libzfs_error_description(zlibh));
149 (void) mutex_unlock(&zlib_mtx);
150 return (rv);
151 }
152 if (snapshot_hold(nlp->nlp_vol,
153 nlp->nlp_snapname, NDMP_RCF_BASENAME) != 0) {
154 syslog(LOG_DEBUG,
155 "backup_dataset_create: %s "
156 "hold failed (err=%d): %s",
157 nlp->nlp_snapname,
158 errno, libzfs_error_description(zlibh));
159 (void) mutex_unlock(&zlib_mtx);
160 return (-1);
161 }
162 syslog(LOG_DEBUG,
163 "Using %s NdmpBackup snapshot for backup",
164 nlp->nlp_snapname);
165
166 }
167
168 if (ndmp_clone_snapshot(nlp) != 0) {
169 syslog(LOG_ERR,
170 "backup_dataset_create: %s clone failed (err=%d): %s",
171 nlp->nlp_snapname, errno, libzfs_error_description(zlibh));
172 (void) mutex_unlock(&zlib_mtx);
173 return (-1);
174 }
175 (void) mutex_unlock(&zlib_mtx);
176 return (0);
177 }
178
179 /*
180 * Unmount, release, and destroy the snapshot created for backup.
181 */
182 int
183 backup_dataset_destroy(ndmp_lbr_params_t *nlp)
184 {
185 char zpoolname[ZFS_MAX_DATASET_NAME_LEN];
186 char *slash;
187 zfs_handle_t *vol_zhp;
188 zfs_handle_t *cln_zhp;
189 int err;
190 int rv = 0;
191
192 if (nlp == NULL) {
193 syslog(LOG_DEBUG,
194 "nlp NULL in backup_dataset_destroy");
195 return (-1);
196 }
197
198 (void) strlcpy(zpoolname, nlp->nlp_vol, sizeof (zpoolname));
199 slash = strchr(zpoolname, '/');
200 if (slash != NULL) {
201 *slash = '\0';
202 }
203
204 if (!NLP_ISCHKPNTED(nlp)) {
205 (void) snprintf(nlp->nlp_snapname, sizeof (nlp->nlp_snapname),
206 "%s@%s", nlp->nlp_vol, nlp->nlp_job_name);
207 }
208
209
210 syslog(LOG_DEBUG, "Snapname in backup_dataset_destroy is [%s]",
211 nlp->nlp_snapname);
212
213 /*
214 * Destroy using this sequence
215 * zfs release <volume>@<jname>
216 * zfs destroy <pool>/<jname>
217 * zfs destroy <pool>/<volume>@<jname>
218 */
219 (void) mutex_lock(&zlib_mtx);
220
221 /*
222 * Release the normal snapshot but don't try to
223 * release if it's a "checkpoint" because the hold
224 * wasn't put on it to begin with.
225 */
226 if (!NLP_ISCHKPNTED(nlp)) {
227 if (snapshot_release(nlp->nlp_vol,
228 nlp->nlp_snapname, NDMP_RCF_BASENAME) != 0) {
229 syslog(LOG_DEBUG,
230 "backup_dataset_destroy: %s "
231 "release failed (err=%d): %s",
232 nlp->nlp_clonename, errno,
233 libzfs_error_description(zlibh));
234 (void) mutex_unlock(&zlib_mtx);
235 return (-1);
236 }
237 } else {
238 syslog(LOG_DEBUG, "Checkpointed dataset not held "
239 "will not release [%s]", nlp->nlp_snapname);
240 }
241
242 /*
243 * Open the clone to get descriptor
244 */
245 if ((cln_zhp = zfs_open(zlibh, nlp->nlp_clonename,
246 ZFS_TYPE_VOLUME | ZFS_TYPE_FILESYSTEM)) == NULL) {
247 syslog(LOG_ERR,
248 "backup_dataset_destroy: open %s failed",
249 nlp->nlp_clonename);
250 (void) mutex_unlock(&zlib_mtx);
251 return (-1);
252 }
253
254 /*
255 * Open the mounted clone to get descriptor for unmount
256 */
257 if ((vol_zhp = zfs_open(zlibh, nlp->nlp_vol,
258 ZFS_TYPE_VOLUME | ZFS_TYPE_FILESYSTEM)) == NULL) {
259 syslog(LOG_ERR,
260 "backup_dataset_destroy: open %s failed [while trying "
261 "to destroy]", nlp->nlp_vol);
262 zfs_close(cln_zhp);
263 (void) mutex_unlock(&zlib_mtx);
264 return (-1);
265 }
266
267 /*
268 * This unmounts the clone which was just traversed for backup
269 */
270 if ((err = zfs_unmount(cln_zhp, NULL, 0)) != 0) {
271 syslog(LOG_INFO, "failed to unmount [%s]", nlp->nlp_clonename);
272 rv = -1;
273 goto _out;
274 }
275
276 /*
277 * This destroys the clone
278 */
279 err = zfs_destroy(cln_zhp, B_TRUE);
280 if (err) {
281 syslog(LOG_ERR, "%s destroy: %d; %s; %s",
282 nlp->nlp_clonename,
283 libzfs_errno(zlibh),
284 libzfs_error_action(zlibh),
285 libzfs_error_description(zlibh));
286 rv = -1;
287 goto _out;
288 }
289
290 /*
291 * This destroys the snapshot of the current backup - but,
292 * don't destroy it if it is an "checkpoint" from AutoSync
293 * or HPR.
294 */
295 if (!NLP_ISCHKPNTED(nlp)) {
296 if ((err = zfs_destroy_snaps(vol_zhp,
297 nlp->nlp_job_name, B_TRUE))) {
298 syslog(LOG_ERR, "%s destroy: %d; %s; %s",
299 nlp->nlp_job_name,
300 libzfs_errno(zlibh),
301 libzfs_error_action(zlibh),
302 libzfs_error_description(zlibh));
303 rv = -1;
304 syslog(LOG_DEBUG, "Destroy [%s]", nlp->nlp_snapname);
305 goto _out;
306 }
307 } else {
308 syslog(LOG_DEBUG, "Checkpointed checkpoint will not destroy [%s]",
309 nlp->nlp_snapname);
310 }
311
312 _out:
313 zfs_close(vol_zhp);
314 zfs_close(cln_zhp);
315 (void) mutex_unlock(&zlib_mtx);
316
317 /*
318 * The zfs_clone() call will have mounted the snapshot
319 * in the file system at this point - so clean it up.
320 */
321 if (rv == 0) {
322 if (rmdir(nlp->nlp_mountpoint) != 0) {
323 syslog(LOG_ERR,
324 "Failed to remove mount point [%s]",
325 nlp->nlp_mountpoint);
326 return (-1);
327 }
328 }
329
330 return (rv);
331 }