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