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