libzfs_iter.c revision 254755
1179337Syongari/* 2179337Syongari * CDDL HEADER START 3179337Syongari * 4179337Syongari * The contents of this file are subject to the terms of the 5179337Syongari * Common Development and Distribution License (the "License"). 6179337Syongari * You may not use this file except in compliance with the License. 7179337Syongari * 8179337Syongari * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9179337Syongari * or http://www.opensolaris.org/os/licensing. 10179337Syongari * See the License for the specific language governing permissions 11179337Syongari * and limitations under the License. 12179337Syongari * 13179337Syongari * When distributing Covered Code, include this CDDL HEADER in each 14179337Syongari * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15179337Syongari * If applicable, add the following below this CDDL HEADER, with the 16179337Syongari * fields enclosed by brackets "[]" replaced with your own identifying 17179337Syongari * information: Portions Copyright [yyyy] [name of copyright owner] 18179337Syongari * 19179337Syongari * CDDL HEADER END 20179337Syongari */ 21179337Syongari 22179337Syongari/* 23179337Syongari * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 24179337Syongari * Copyright (c) 2012 by Delphix. All rights reserved. 25179337Syongari * Copyright (c) 2012 Pawel Jakub Dawidek <pawel@dawidek.net>. 26179337Syongari * All rights reserved. 27179337Syongari * Copyright 2013 Nexenta Systems, Inc. All rights reserved. 28179337Syongari */ 29179337Syongari 30179337Syongari#include <stdio.h> 31179337Syongari#include <stdlib.h> 32179337Syongari#include <strings.h> 33179337Syongari#include <unistd.h> 34179337Syongari#include <stddef.h> 35179337Syongari#include <libintl.h> 36179337Syongari#include <libzfs.h> 37179337Syongari 38179337Syongari#include "libzfs_impl.h" 39179337Syongari 40179337Syongariint 41179337Syongarizfs_iter_clones(zfs_handle_t *zhp, zfs_iter_f func, void *data) 42179337Syongari{ 43179337Syongari nvlist_t *nvl = zfs_get_clones_nvl(zhp); 44179337Syongari nvpair_t *pair; 45179337Syongari 46179337Syongari if (nvl == NULL) 47179337Syongari return (0); 48179337Syongari 49179337Syongari for (pair = nvlist_next_nvpair(nvl, NULL); pair != NULL; 50179337Syongari pair = nvlist_next_nvpair(nvl, pair)) { 51179337Syongari zfs_handle_t *clone = zfs_open(zhp->zfs_hdl, nvpair_name(pair), 52264442Syongari ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME); 53179337Syongari if (clone != NULL) { 54179337Syongari int err = func(clone, data); 55179337Syongari if (err != 0) 56179337Syongari return (err); 57179337Syongari } 58179337Syongari } 59179337Syongari return (0); 60179337Syongari} 61179337Syongari 62179337Syongaristatic int 63179337Syongarizfs_do_list_ioctl(zfs_handle_t *zhp, unsigned long arg, zfs_cmd_t *zc) 64179337Syongari{ 65179337Syongari int rc; 66179337Syongari uint64_t orig_cookie; 67179337Syongari 68179337Syongari orig_cookie = zc->zc_cookie; 69216546Syongaritop: 70216546Syongari (void) strlcpy(zc->zc_name, zhp->zfs_name, sizeof (zc->zc_name)); 71179337Syongari rc = ioctl(zhp->zfs_hdl->libzfs_fd, arg, zc); 72179337Syongari 73179337Syongari if (rc == -1) { 74179337Syongari switch (errno) { 75179337Syongari case ENOMEM: 76179337Syongari /* expand nvlist memory and try again */ 77179337Syongari if (zcmd_expand_dst_nvlist(zhp->zfs_hdl, zc) != 0) { 78179337Syongari zcmd_free_nvlists(zc); 79179337Syongari return (-1); 80179337Syongari } 81179337Syongari zc->zc_cookie = orig_cookie; 82179337Syongari goto top; 83179337Syongari /* 84179337Syongari * An errno value of ESRCH indicates normal completion. 85179337Syongari * If ENOENT is returned, then the underlying dataset 86179337Syongari * has been removed since we obtained the handle. 87179337Syongari */ 88179337Syongari case ESRCH: 89179337Syongari case ENOENT: 90179337Syongari rc = 1; 91179337Syongari break; 92179337Syongari default: 93179337Syongari rc = zfs_standard_error(zhp->zfs_hdl, errno, 94179337Syongari dgettext(TEXT_DOMAIN, 95179337Syongari "cannot iterate filesystems")); 96179337Syongari break; 97179337Syongari } 98179337Syongari } 99179337Syongari return (rc); 100179337Syongari} 101179337Syongari 102179337Syongari/* 103179337Syongari * Iterate over all child filesystems 104179337Syongari */ 105179337Syongariint 106179337Syongarizfs_iter_filesystems(zfs_handle_t *zhp, zfs_iter_f func, void *data) 107179337Syongari{ 108179337Syongari zfs_cmd_t zc = { 0 }; 109179337Syongari zfs_handle_t *nzhp; 110179337Syongari int ret; 111179337Syongari 112179337Syongari if (zhp->zfs_type != ZFS_TYPE_FILESYSTEM) 113179337Syongari return (0); 114179337Syongari 115179337Syongari if (zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0) != 0) 116179337Syongari return (-1); 117179337Syongari 118179337Syongari while ((ret = zfs_do_list_ioctl(zhp, ZFS_IOC_DATASET_LIST_NEXT, 119179337Syongari &zc)) == 0) { 120179337Syongari /* 121179337Syongari * Silently ignore errors, as the only plausible explanation is 122179337Syongari * that the pool has since been removed. 123179337Syongari */ 124179337Syongari if ((nzhp = make_dataset_handle_zc(zhp->zfs_hdl, 125179337Syongari &zc)) == NULL) { 126179337Syongari continue; 127179337Syongari } 128179337Syongari 129179337Syongari if ((ret = func(nzhp, data)) != 0) { 130179337Syongari zcmd_free_nvlists(&zc); 131179337Syongari return (ret); 132179337Syongari } 133179337Syongari } 134179337Syongari zcmd_free_nvlists(&zc); 135179337Syongari return ((ret < 0) ? ret : 0); 136179337Syongari} 137179337Syongari 138179337Syongari/* 139179337Syongari * Iterate over all snapshots 140179337Syongari */ 141179337Syongariint 142179337Syongarizfs_iter_snapshots(zfs_handle_t *zhp, boolean_t simple, zfs_iter_f func, 143179337Syongari void *data) 144179337Syongari{ 145179337Syongari zfs_cmd_t zc = { 0 }; 146216546Syongari zfs_handle_t *nzhp; 147179337Syongari int ret; 148216546Syongari 149179337Syongari if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) 150179337Syongari return (0); 151216546Syongari 152179337Syongari zc.zc_simple = simple; 153216546Syongari 154179337Syongari if (zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0) != 0) 155179337Syongari return (-1); 156179337Syongari while ((ret = zfs_do_list_ioctl(zhp, ZFS_IOC_SNAPSHOT_LIST_NEXT, 157185597Syongari &zc)) == 0) { 158185597Syongari 159185597Syongari if (simple) 160185597Syongari nzhp = make_dataset_simple_handle_zc(zhp, &zc); 161185597Syongari else 162185597Syongari nzhp = make_dataset_handle_zc(zhp->zfs_hdl, &zc); 163185597Syongari if (nzhp == NULL) 164185597Syongari continue; 165185597Syongari 166185597Syongari if ((ret = func(nzhp, data)) != 0) { 167185597Syongari zcmd_free_nvlists(&zc); 168185597Syongari return (ret); 169179337Syongari } 170179337Syongari } 171179337Syongari zcmd_free_nvlists(&zc); 172179337Syongari return ((ret < 0) ? ret : 0); 173179337Syongari} 174179337Syongari 175179337Syongari/* 176179337Syongari * Routines for dealing with the sorted snapshot functionality 177179337Syongari */ 178179337Syongaritypedef struct zfs_node { 179179337Syongari zfs_handle_t *zn_handle; 180179337Syongari avl_node_t zn_avlnode; 181179337Syongari} zfs_node_t; 182179337Syongari 183179337Syongaristatic int 184179337Syongarizfs_sort_snaps(zfs_handle_t *zhp, void *data) 185179337Syongari{ 186179337Syongari avl_tree_t *avl = data; 187179337Syongari zfs_node_t *node; 188216551Syongari zfs_node_t search; 189216551Syongari 190216551Syongari search.zn_handle = zhp; 191216551Syongari node = avl_find(avl, &search, NULL); 192216551Syongari if (node) { 193216551Syongari /* 194216551Syongari * If this snapshot was renamed while we were creating the 195216551Syongari * AVL tree, it's possible that we already inserted it under 196216551Syongari * its old name. Remove the old handle before adding the new 197216551Syongari * one. 198216551Syongari */ 199216551Syongari zfs_close(node->zn_handle); 200216551Syongari avl_remove(avl, node); 201216551Syongari free(node); 202216551Syongari } 203216551Syongari 204179337Syongari node = zfs_alloc(zhp->zfs_hdl, sizeof (zfs_node_t)); 205185597Syongari node->zn_handle = zhp; 206185597Syongari avl_add(avl, node); 207179337Syongari 208179337Syongari return (0); 209179337Syongari} 210179337Syongari 211179337Syongaristatic int 212179337Syongarizfs_snapshot_compare(const void *larg, const void *rarg) 213179337Syongari{ 214179337Syongari zfs_handle_t *l = ((zfs_node_t *)larg)->zn_handle; 215179337Syongari zfs_handle_t *r = ((zfs_node_t *)rarg)->zn_handle; 216216551Syongari uint64_t lcreate, rcreate; 217179337Syongari 218179337Syongari /* 219216551Syongari * Sort them according to creation time. We use the hidden 220179337Syongari * CREATETXG property to get an absolute ordering of snapshots. 221179337Syongari */ 222179337Syongari lcreate = zfs_prop_get_int(l, ZFS_PROP_CREATETXG); 223179337Syongari rcreate = zfs_prop_get_int(r, ZFS_PROP_CREATETXG); 224179337Syongari 225179337Syongari if (lcreate < rcreate) 226179337Syongari return (-1); 227179337Syongari else if (lcreate > rcreate) 228179337Syongari return (+1); 229179337Syongari else 230216546Syongari return (0); 231179337Syongari} 232216546Syongari 233179337Syongariint 234179337Syongarizfs_iter_snapshots_sorted(zfs_handle_t *zhp, zfs_iter_f callback, void *data) 235216546Syongari{ 236216546Syongari int ret = 0; 237216546Syongari zfs_node_t *node; 238179337Syongari avl_tree_t avl; 239179337Syongari void *cookie = NULL; 240179337Syongari 241179337Syongari avl_create(&avl, zfs_snapshot_compare, 242179337Syongari sizeof (zfs_node_t), offsetof(zfs_node_t, zn_avlnode)); 243179337Syongari 244179337Syongari ret = zfs_iter_snapshots(zhp, B_FALSE, zfs_sort_snaps, &avl); 245179337Syongari 246179337Syongari for (node = avl_first(&avl); node != NULL; node = AVL_NEXT(&avl, node)) 247179337Syongari ret |= callback(node->zn_handle, data); 248179337Syongari 249216546Syongari while ((node = avl_destroy_nodes(&avl, &cookie)) != NULL) 250216546Syongari free(node); 251216546Syongari 252179337Syongari avl_destroy(&avl); 253179337Syongari 254 return (ret); 255} 256 257typedef struct { 258 char *ssa_first; 259 char *ssa_last; 260 boolean_t ssa_seenfirst; 261 boolean_t ssa_seenlast; 262 zfs_iter_f ssa_func; 263 void *ssa_arg; 264} snapspec_arg_t; 265 266static int 267snapspec_cb(zfs_handle_t *zhp, void *arg) { 268 snapspec_arg_t *ssa = arg; 269 char *shortsnapname; 270 int err = 0; 271 272 if (ssa->ssa_seenlast) 273 return (0); 274 shortsnapname = zfs_strdup(zhp->zfs_hdl, 275 strchr(zfs_get_name(zhp), '@') + 1); 276 277 if (!ssa->ssa_seenfirst && strcmp(shortsnapname, ssa->ssa_first) == 0) 278 ssa->ssa_seenfirst = B_TRUE; 279 280 if (ssa->ssa_seenfirst) { 281 err = ssa->ssa_func(zhp, ssa->ssa_arg); 282 } else { 283 zfs_close(zhp); 284 } 285 286 if (strcmp(shortsnapname, ssa->ssa_last) == 0) 287 ssa->ssa_seenlast = B_TRUE; 288 free(shortsnapname); 289 290 return (err); 291} 292 293/* 294 * spec is a string like "A,B%C,D" 295 * 296 * <snaps>, where <snaps> can be: 297 * <snap> (single snapshot) 298 * <snap>%<snap> (range of snapshots, inclusive) 299 * %<snap> (range of snapshots, starting with earliest) 300 * <snap>% (range of snapshots, ending with last) 301 * % (all snapshots) 302 * <snaps>[,...] (comma separated list of the above) 303 * 304 * If a snapshot can not be opened, continue trying to open the others, but 305 * return ENOENT at the end. 306 */ 307int 308zfs_iter_snapspec(zfs_handle_t *fs_zhp, const char *spec_orig, 309 zfs_iter_f func, void *arg) 310{ 311 char *buf, *comma_separated, *cp; 312 int err = 0; 313 int ret = 0; 314 315 buf = zfs_strdup(fs_zhp->zfs_hdl, spec_orig); 316 cp = buf; 317 318 while ((comma_separated = strsep(&cp, ",")) != NULL) { 319 char *pct = strchr(comma_separated, '%'); 320 if (pct != NULL) { 321 snapspec_arg_t ssa = { 0 }; 322 ssa.ssa_func = func; 323 ssa.ssa_arg = arg; 324 325 if (pct == comma_separated) 326 ssa.ssa_seenfirst = B_TRUE; 327 else 328 ssa.ssa_first = comma_separated; 329 *pct = '\0'; 330 ssa.ssa_last = pct + 1; 331 332 /* 333 * If there is a lastname specified, make sure it 334 * exists. 335 */ 336 if (ssa.ssa_last[0] != '\0') { 337 char snapname[ZFS_MAXNAMELEN]; 338 (void) snprintf(snapname, sizeof (snapname), 339 "%s@%s", zfs_get_name(fs_zhp), 340 ssa.ssa_last); 341 if (!zfs_dataset_exists(fs_zhp->zfs_hdl, 342 snapname, ZFS_TYPE_SNAPSHOT)) { 343 ret = ENOENT; 344 continue; 345 } 346 } 347 348 err = zfs_iter_snapshots_sorted(fs_zhp, 349 snapspec_cb, &ssa); 350 if (ret == 0) 351 ret = err; 352 if (ret == 0 && (!ssa.ssa_seenfirst || 353 (ssa.ssa_last[0] != '\0' && !ssa.ssa_seenlast))) { 354 ret = ENOENT; 355 } 356 } else { 357 char snapname[ZFS_MAXNAMELEN]; 358 zfs_handle_t *snap_zhp; 359 (void) snprintf(snapname, sizeof (snapname), "%s@%s", 360 zfs_get_name(fs_zhp), comma_separated); 361 snap_zhp = make_dataset_handle(fs_zhp->zfs_hdl, 362 snapname); 363 if (snap_zhp == NULL) { 364 ret = ENOENT; 365 continue; 366 } 367 err = func(snap_zhp, arg); 368 if (ret == 0) 369 ret = err; 370 } 371 } 372 373 free(buf); 374 return (ret); 375} 376 377/* 378 * Iterate over all children, snapshots and filesystems 379 */ 380int 381zfs_iter_children(zfs_handle_t *zhp, zfs_iter_f func, void *data) 382{ 383 int ret; 384 385 if ((ret = zfs_iter_filesystems(zhp, func, data)) != 0) 386 return (ret); 387 388 return (zfs_iter_snapshots(zhp, B_FALSE, func, data)); 389} 390 391 392typedef struct iter_stack_frame { 393 struct iter_stack_frame *next; 394 zfs_handle_t *zhp; 395} iter_stack_frame_t; 396 397typedef struct iter_dependents_arg { 398 boolean_t first; 399 boolean_t allowrecursion; 400 iter_stack_frame_t *stack; 401 zfs_iter_f func; 402 void *data; 403} iter_dependents_arg_t; 404 405static int 406iter_dependents_cb(zfs_handle_t *zhp, void *arg) 407{ 408 iter_dependents_arg_t *ida = arg; 409 int err; 410 boolean_t first = ida->first; 411 ida->first = B_FALSE; 412 413 if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) { 414 err = zfs_iter_clones(zhp, iter_dependents_cb, ida); 415 } else { 416 iter_stack_frame_t isf; 417 iter_stack_frame_t *f; 418 419 /* 420 * check if there is a cycle by seeing if this fs is already 421 * on the stack. 422 */ 423 for (f = ida->stack; f != NULL; f = f->next) { 424 if (f->zhp->zfs_dmustats.dds_guid == 425 zhp->zfs_dmustats.dds_guid) { 426 if (ida->allowrecursion) { 427 zfs_close(zhp); 428 return (0); 429 } else { 430 zfs_error_aux(zhp->zfs_hdl, 431 dgettext(TEXT_DOMAIN, 432 "recursive dependency at '%s'"), 433 zfs_get_name(zhp)); 434 err = zfs_error(zhp->zfs_hdl, 435 EZFS_RECURSIVE, 436 dgettext(TEXT_DOMAIN, 437 "cannot determine dependent " 438 "datasets")); 439 zfs_close(zhp); 440 return (err); 441 } 442 } 443 } 444 445 isf.zhp = zhp; 446 isf.next = ida->stack; 447 ida->stack = &isf; 448 err = zfs_iter_filesystems(zhp, iter_dependents_cb, ida); 449 if (err == 0) { 450 err = zfs_iter_snapshots(zhp, B_FALSE, 451 iter_dependents_cb, ida); 452 } 453 ida->stack = isf.next; 454 } 455 456 if (!first && err == 0) 457 err = ida->func(zhp, ida->data); 458 else 459 zfs_close(zhp); 460 461 return (err); 462} 463 464int 465zfs_iter_dependents(zfs_handle_t *zhp, boolean_t allowrecursion, 466 zfs_iter_f func, void *data) 467{ 468 iter_dependents_arg_t ida; 469 ida.allowrecursion = allowrecursion; 470 ida.stack = NULL; 471 ida.func = func; 472 ida.data = data; 473 ida.first = B_TRUE; 474 return (iter_dependents_cb(zfs_handle_dup(zhp), &ida)); 475} 476