Print this page
NEX-3669 Faults for fans that don't exist
Reviewed by: Jeffry Molanus <jeffry.molanus@nexenta.com>
NEX-3891 Hide the snapshots that belong to in-kernel autosnap-service
Reviewed by: Josef 'Jeff' Sipek <josef.sipek@nexenta.com>
Reviewed by: Alek Pinchuk <alek@nexenta.com>
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/cmd/zfs/zfs_iter.c
+++ new/usr/src/cmd/zfs/zfs_iter.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
24 24 * Copyright (c) 2012 Pawel Jakub Dawidek. All rights reserved.
25 25 * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
26 26 * Copyright (c) 2013 by Delphix. All rights reserved.
27 27 */
28 28
29 29 #include <libintl.h>
30 30 #include <libuutil.h>
31 31 #include <stddef.h>
32 32 #include <stdio.h>
33 33 #include <stdlib.h>
34 34 #include <strings.h>
35 35
36 36 #include <libzfs.h>
37 37
38 38 #include "zfs_util.h"
39 39 #include "zfs_iter.h"
40 40
41 41 /*
42 42 * This is a private interface used to gather up all the datasets specified on
43 43 * the command line so that we can iterate over them in order.
44 44 *
45 45 * First, we iterate over all filesystems, gathering them together into an
46 46 * AVL tree. We report errors for any explicitly specified datasets
47 47 * that we couldn't open.
48 48 *
49 49 * When finished, we have an AVL tree of ZFS handles. We go through and execute
50 50 * the provided callback for each one, passing whatever data the user supplied.
51 51 */
52 52
53 53 typedef struct zfs_node {
54 54 zfs_handle_t *zn_handle;
55 55 uu_avl_node_t zn_avlnode;
56 56 } zfs_node_t;
57 57
58 58 typedef struct callback_data {
59 59 uu_avl_t *cb_avl;
60 60 int cb_flags;
61 61 zfs_type_t cb_types;
62 62 zfs_sort_column_t *cb_sortcol;
63 63 zprop_list_t **cb_proplist;
64 64 int cb_depth_limit;
65 65 int cb_depth;
66 66 uint8_t cb_props_table[ZFS_NUM_PROPS];
67 67 } callback_data_t;
68 68
69 69 uu_avl_pool_t *avl_pool;
70 70
71 71 /*
72 72 * Include snaps if they were requested or if this a zfs list where types
73 73 * were not specified and the "listsnapshots" property is set on this pool.
74 74 */
75 75 static boolean_t
76 76 zfs_include_snapshots(zfs_handle_t *zhp, callback_data_t *cb)
77 77 {
78 78 zpool_handle_t *zph;
79 79
80 80 if ((cb->cb_flags & ZFS_ITER_PROP_LISTSNAPS) == 0)
81 81 return (cb->cb_types & ZFS_TYPE_SNAPSHOT);
82 82
83 83 zph = zfs_get_pool_handle(zhp);
84 84 return (zpool_get_prop_int(zph, ZPOOL_PROP_LISTSNAPS, NULL));
85 85 }
86 86
87 87 /*
|
↓ open down ↓ |
87 lines elided |
↑ open up ↑ |
88 88 * Called for each dataset. If the object is of an appropriate type,
89 89 * add it to the avl tree and recurse over any children as necessary.
90 90 */
91 91 static int
92 92 zfs_callback(zfs_handle_t *zhp, void *data)
93 93 {
94 94 callback_data_t *cb = data;
95 95 boolean_t should_close = B_TRUE;
96 96 boolean_t include_snaps = zfs_include_snapshots(zhp, cb);
97 97 boolean_t include_bmarks = (cb->cb_types & ZFS_TYPE_BOOKMARK);
98 + boolean_t include_autosnaps =
99 + ((cb->cb_types & ZFS_TYPE_AUTOSNAP) &&
100 + !(cb->cb_flags & ZFS_ITER_PROP_LISTSNAPS));
98 101
99 102 if ((zfs_get_type(zhp) & cb->cb_types) ||
100 103 ((zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT) && include_snaps)) {
101 104 uu_avl_index_t idx;
102 105 zfs_node_t *node = safe_malloc(sizeof (zfs_node_t));
103 106
104 107 node->zn_handle = zhp;
105 108 uu_avl_node_init(node, &node->zn_avlnode, avl_pool);
106 109 if (uu_avl_find(cb->cb_avl, node, cb->cb_sortcol,
107 110 &idx) == NULL) {
108 111 if (cb->cb_proplist) {
109 112 if ((*cb->cb_proplist) &&
110 113 !(*cb->cb_proplist)->pl_all)
111 114 zfs_prune_proplist(zhp,
112 115 cb->cb_props_table);
113 116
114 117 if (zfs_expand_proplist(zhp, cb->cb_proplist,
115 118 (cb->cb_flags & ZFS_ITER_RECVD_PROPS),
116 119 (cb->cb_flags & ZFS_ITER_LITERAL_PROPS))
117 120 != 0) {
118 121 free(node);
119 122 return (-1);
120 123 }
121 124 }
122 125 uu_avl_insert(cb->cb_avl, node, idx);
123 126 should_close = B_FALSE;
124 127 } else {
125 128 free(node);
126 129 }
127 130 }
128 131
|
↓ open down ↓ |
21 lines elided |
↑ open up ↑ |
129 132 /*
130 133 * Recurse if necessary.
131 134 */
132 135 if (cb->cb_flags & ZFS_ITER_RECURSE &&
133 136 ((cb->cb_flags & ZFS_ITER_DEPTH_LIMIT) == 0 ||
134 137 cb->cb_depth < cb->cb_depth_limit)) {
135 138 cb->cb_depth++;
136 139 if (zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM)
137 140 (void) zfs_iter_filesystems(zhp, zfs_callback, data);
138 141 if (((zfs_get_type(zhp) & (ZFS_TYPE_SNAPSHOT |
139 - ZFS_TYPE_BOOKMARK)) == 0) && include_snaps)
140 - (void) zfs_iter_snapshots(zhp,
141 - (cb->cb_flags & ZFS_ITER_SIMPLE) != 0, zfs_callback,
142 - data);
142 + ZFS_TYPE_BOOKMARK | ZFS_TYPE_AUTOSNAP)) == 0)) {
143 + if (include_snaps) {
144 + (void) zfs_iter_snapshots(zhp,
145 + (cb->cb_flags & ZFS_ITER_SIMPLE) != 0,
146 + zfs_callback, data);
147 + }
148 +
149 + if (include_autosnaps) {
150 + (void) zfs_iter_autosnapshots(zhp,
151 + (cb->cb_flags & ZFS_ITER_SIMPLE) != 0,
152 + zfs_callback, data);
153 + }
154 + }
155 +
143 156 if (((zfs_get_type(zhp) & (ZFS_TYPE_SNAPSHOT |
144 157 ZFS_TYPE_BOOKMARK)) == 0) && include_bmarks)
145 158 (void) zfs_iter_bookmarks(zhp, zfs_callback, data);
146 159 cb->cb_depth--;
147 160 }
148 161
149 162 if (should_close)
150 163 zfs_close(zhp);
151 164
152 165 return (0);
153 166 }
154 167
155 168 int
156 169 zfs_add_sort_column(zfs_sort_column_t **sc, const char *name,
157 170 boolean_t reverse)
158 171 {
159 172 zfs_sort_column_t *col;
160 173 zfs_prop_t prop;
161 174
162 175 if ((prop = zfs_name_to_prop(name)) == ZPROP_INVAL &&
163 176 !zfs_prop_user(name))
164 177 return (-1);
165 178
166 179 col = safe_malloc(sizeof (zfs_sort_column_t));
167 180
168 181 col->sc_prop = prop;
169 182 col->sc_reverse = reverse;
170 183 if (prop == ZPROP_INVAL) {
171 184 col->sc_user_prop = safe_malloc(strlen(name) + 1);
172 185 (void) strcpy(col->sc_user_prop, name);
173 186 }
174 187
175 188 if (*sc == NULL) {
176 189 col->sc_last = col;
177 190 *sc = col;
178 191 } else {
179 192 (*sc)->sc_last->sc_next = col;
180 193 (*sc)->sc_last = col;
181 194 }
182 195
183 196 return (0);
184 197 }
185 198
186 199 void
187 200 zfs_free_sort_columns(zfs_sort_column_t *sc)
188 201 {
189 202 zfs_sort_column_t *col;
190 203
191 204 while (sc != NULL) {
192 205 col = sc->sc_next;
193 206 free(sc->sc_user_prop);
194 207 free(sc);
195 208 sc = col;
196 209 }
197 210 }
198 211
199 212 boolean_t
200 213 zfs_sort_only_by_name(const zfs_sort_column_t *sc)
201 214 {
202 215
203 216 return (sc != NULL && sc->sc_next == NULL &&
204 217 sc->sc_prop == ZFS_PROP_NAME);
205 218 }
206 219
207 220 /* ARGSUSED */
208 221 static int
209 222 zfs_compare(const void *larg, const void *rarg, void *unused)
210 223 {
211 224 zfs_handle_t *l = ((zfs_node_t *)larg)->zn_handle;
212 225 zfs_handle_t *r = ((zfs_node_t *)rarg)->zn_handle;
213 226 const char *lname = zfs_get_name(l);
214 227 const char *rname = zfs_get_name(r);
215 228 char *lat, *rat;
216 229 uint64_t lcreate, rcreate;
217 230 int ret;
218 231
219 232 lat = (char *)strchr(lname, '@');
220 233 rat = (char *)strchr(rname, '@');
221 234
222 235 if (lat != NULL)
223 236 *lat = '\0';
224 237 if (rat != NULL)
225 238 *rat = '\0';
226 239
227 240 ret = strcmp(lname, rname);
228 241 if (ret == 0) {
229 242 /*
230 243 * If we're comparing a dataset to one of its snapshots, we
231 244 * always make the full dataset first.
232 245 */
233 246 if (lat == NULL) {
234 247 ret = -1;
235 248 } else if (rat == NULL) {
236 249 ret = 1;
237 250 } else {
238 251 /*
239 252 * If we have two snapshots from the same dataset, then
240 253 * we want to sort them according to creation time. We
241 254 * use the hidden CREATETXG property to get an absolute
242 255 * ordering of snapshots.
243 256 */
244 257 lcreate = zfs_prop_get_int(l, ZFS_PROP_CREATETXG);
245 258 rcreate = zfs_prop_get_int(r, ZFS_PROP_CREATETXG);
246 259
247 260 /*
248 261 * Both lcreate and rcreate being 0 means we don't have
249 262 * properties and we should compare full name.
250 263 */
251 264 if (lcreate == 0 && rcreate == 0)
252 265 ret = strcmp(lat + 1, rat + 1);
253 266 else if (lcreate < rcreate)
254 267 ret = -1;
255 268 else if (lcreate > rcreate)
256 269 ret = 1;
257 270 }
258 271 }
259 272
260 273 if (lat != NULL)
261 274 *lat = '@';
262 275 if (rat != NULL)
263 276 *rat = '@';
264 277
265 278 return (ret);
266 279 }
267 280
268 281 /*
269 282 * Sort datasets by specified columns.
270 283 *
271 284 * o Numeric types sort in ascending order.
272 285 * o String types sort in alphabetical order.
273 286 * o Types inappropriate for a row sort that row to the literal
274 287 * bottom, regardless of the specified ordering.
275 288 *
276 289 * If no sort columns are specified, or two datasets compare equally
277 290 * across all specified columns, they are sorted alphabetically by name
278 291 * with snapshots grouped under their parents.
279 292 */
280 293 static int
281 294 zfs_sort(const void *larg, const void *rarg, void *data)
282 295 {
283 296 zfs_handle_t *l = ((zfs_node_t *)larg)->zn_handle;
284 297 zfs_handle_t *r = ((zfs_node_t *)rarg)->zn_handle;
285 298 zfs_sort_column_t *sc = (zfs_sort_column_t *)data;
286 299 zfs_sort_column_t *psc;
287 300
288 301 for (psc = sc; psc != NULL; psc = psc->sc_next) {
289 302 char lbuf[ZFS_MAXPROPLEN], rbuf[ZFS_MAXPROPLEN];
290 303 char *lstr, *rstr;
291 304 uint64_t lnum, rnum;
292 305 boolean_t lvalid, rvalid;
293 306 int ret = 0;
294 307
295 308 /*
296 309 * We group the checks below the generic code. If 'lstr' and
297 310 * 'rstr' are non-NULL, then we do a string based comparison.
298 311 * Otherwise, we compare 'lnum' and 'rnum'.
299 312 */
300 313 lstr = rstr = NULL;
301 314 if (psc->sc_prop == ZPROP_INVAL) {
302 315 nvlist_t *luser, *ruser;
303 316 nvlist_t *lval, *rval;
304 317
305 318 luser = zfs_get_user_props(l);
306 319 ruser = zfs_get_user_props(r);
307 320
308 321 lvalid = (nvlist_lookup_nvlist(luser,
309 322 psc->sc_user_prop, &lval) == 0);
310 323 rvalid = (nvlist_lookup_nvlist(ruser,
311 324 psc->sc_user_prop, &rval) == 0);
312 325
313 326 if (lvalid)
314 327 verify(nvlist_lookup_string(lval,
315 328 ZPROP_VALUE, &lstr) == 0);
316 329 if (rvalid)
317 330 verify(nvlist_lookup_string(rval,
318 331 ZPROP_VALUE, &rstr) == 0);
319 332 } else if (psc->sc_prop == ZFS_PROP_NAME) {
320 333 lvalid = rvalid = B_TRUE;
321 334
322 335 (void) strlcpy(lbuf, zfs_get_name(l), sizeof (lbuf));
323 336 (void) strlcpy(rbuf, zfs_get_name(r), sizeof (rbuf));
324 337
325 338 lstr = lbuf;
326 339 rstr = rbuf;
327 340 } else if (zfs_prop_is_string(psc->sc_prop)) {
328 341 lvalid = (zfs_prop_get(l, psc->sc_prop, lbuf,
329 342 sizeof (lbuf), NULL, NULL, 0, B_TRUE) == 0);
330 343 rvalid = (zfs_prop_get(r, psc->sc_prop, rbuf,
331 344 sizeof (rbuf), NULL, NULL, 0, B_TRUE) == 0);
332 345
333 346 lstr = lbuf;
334 347 rstr = rbuf;
335 348 } else {
336 349 lvalid = zfs_prop_valid_for_type(psc->sc_prop,
337 350 zfs_get_type(l));
338 351 rvalid = zfs_prop_valid_for_type(psc->sc_prop,
339 352 zfs_get_type(r));
340 353
341 354 if (lvalid)
342 355 (void) zfs_prop_get_numeric(l, psc->sc_prop,
343 356 &lnum, NULL, NULL, 0);
344 357 if (rvalid)
345 358 (void) zfs_prop_get_numeric(r, psc->sc_prop,
346 359 &rnum, NULL, NULL, 0);
347 360 }
348 361
349 362 if (!lvalid && !rvalid)
350 363 continue;
351 364 else if (!lvalid)
352 365 return (1);
353 366 else if (!rvalid)
354 367 return (-1);
355 368
356 369 if (lstr)
357 370 ret = strcmp(lstr, rstr);
358 371 else if (lnum < rnum)
359 372 ret = -1;
360 373 else if (lnum > rnum)
361 374 ret = 1;
362 375
363 376 if (ret != 0) {
364 377 if (psc->sc_reverse == B_TRUE)
365 378 ret = (ret < 0) ? 1 : -1;
366 379 return (ret);
367 380 }
368 381 }
369 382
370 383 return (zfs_compare(larg, rarg, NULL));
371 384 }
372 385
373 386 int
374 387 zfs_for_each(int argc, char **argv, int flags, zfs_type_t types,
375 388 zfs_sort_column_t *sortcol, zprop_list_t **proplist, int limit,
376 389 zfs_iter_f callback, void *data)
377 390 {
378 391 callback_data_t cb = {0};
379 392 int ret = 0;
380 393 zfs_node_t *node;
381 394 uu_avl_walk_t *walk;
382 395
383 396 avl_pool = uu_avl_pool_create("zfs_pool", sizeof (zfs_node_t),
384 397 offsetof(zfs_node_t, zn_avlnode), zfs_sort, UU_DEFAULT);
385 398
386 399 if (avl_pool == NULL)
387 400 nomem();
388 401
389 402 cb.cb_sortcol = sortcol;
390 403 cb.cb_flags = flags;
391 404 cb.cb_proplist = proplist;
392 405 cb.cb_types = types;
393 406 cb.cb_depth_limit = limit;
394 407 /*
395 408 * If cb_proplist is provided then in the zfs_handles created we
396 409 * retain only those properties listed in cb_proplist and sortcol.
397 410 * The rest are pruned. So, the caller should make sure that no other
398 411 * properties other than those listed in cb_proplist/sortcol are
399 412 * accessed.
400 413 *
401 414 * If cb_proplist is NULL then we retain all the properties. We
402 415 * always retain the zoned property, which some other properties
403 416 * need (userquota & friends), and the createtxg property, which
404 417 * we need to sort snapshots.
405 418 */
406 419 if (cb.cb_proplist && *cb.cb_proplist) {
407 420 zprop_list_t *p = *cb.cb_proplist;
408 421
409 422 while (p) {
410 423 if (p->pl_prop >= ZFS_PROP_TYPE &&
411 424 p->pl_prop < ZFS_NUM_PROPS) {
412 425 cb.cb_props_table[p->pl_prop] = B_TRUE;
413 426 }
414 427 p = p->pl_next;
415 428 }
416 429
417 430 while (sortcol) {
418 431 if (sortcol->sc_prop >= ZFS_PROP_TYPE &&
419 432 sortcol->sc_prop < ZFS_NUM_PROPS) {
420 433 cb.cb_props_table[sortcol->sc_prop] = B_TRUE;
421 434 }
422 435 sortcol = sortcol->sc_next;
423 436 }
424 437
425 438 cb.cb_props_table[ZFS_PROP_ZONED] = B_TRUE;
426 439 cb.cb_props_table[ZFS_PROP_CREATETXG] = B_TRUE;
427 440 } else {
428 441 (void) memset(cb.cb_props_table, B_TRUE,
429 442 sizeof (cb.cb_props_table));
430 443 }
431 444
432 445 if ((cb.cb_avl = uu_avl_create(avl_pool, NULL, UU_DEFAULT)) == NULL)
433 446 nomem();
434 447
435 448 if (argc == 0) {
436 449 /*
437 450 * If given no arguments, iterate over all datasets.
438 451 */
439 452 cb.cb_flags |= ZFS_ITER_RECURSE;
440 453 ret = zfs_iter_root(g_zfs, zfs_callback, &cb);
441 454 } else {
442 455 int i;
443 456 zfs_handle_t *zhp;
444 457 zfs_type_t argtype;
445 458
446 459 /*
447 460 * If we're recursive, then we always allow filesystems as
448 461 * arguments. If we also are interested in snapshots, then we
449 462 * can take volumes as well.
450 463 */
451 464 argtype = types;
452 465 if (flags & ZFS_ITER_RECURSE) {
453 466 argtype |= ZFS_TYPE_FILESYSTEM;
454 467 if (types & ZFS_TYPE_SNAPSHOT)
455 468 argtype |= ZFS_TYPE_VOLUME;
456 469 }
457 470
458 471 for (i = 0; i < argc; i++) {
459 472 if (flags & ZFS_ITER_ARGS_CAN_BE_PATHS) {
460 473 zhp = zfs_path_to_zhandle(g_zfs, argv[i],
461 474 argtype);
462 475 } else {
463 476 zhp = zfs_open(g_zfs, argv[i], argtype);
464 477 }
465 478 if (zhp != NULL)
466 479 ret |= zfs_callback(zhp, &cb);
467 480 else
468 481 ret = 1;
469 482 }
470 483 }
471 484
472 485 /*
473 486 * At this point we've got our AVL tree full of zfs handles, so iterate
474 487 * over each one and execute the real user callback.
475 488 */
476 489 for (node = uu_avl_first(cb.cb_avl); node != NULL;
477 490 node = uu_avl_next(cb.cb_avl, node))
478 491 ret |= callback(node->zn_handle, data);
479 492
480 493 /*
481 494 * Finally, clean up the AVL tree.
482 495 */
483 496 if ((walk = uu_avl_walk_start(cb.cb_avl, UU_WALK_ROBUST)) == NULL)
484 497 nomem();
485 498
486 499 while ((node = uu_avl_walk_next(walk)) != NULL) {
487 500 uu_avl_remove(cb.cb_avl, node);
488 501 zfs_close(node->zn_handle);
489 502 free(node);
490 503 }
491 504
492 505 uu_avl_walk_end(walk);
493 506 uu_avl_destroy(cb.cb_avl);
494 507 uu_avl_pool_destroy(avl_pool);
495 508
496 509 return (ret);
497 510 }
|
↓ open down ↓ |
345 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX