int zvol_set_snapdev(const char *dsname, uint64_t snapdev) { (void) dmu_objset_find((char *) dsname, snapdev_snapshot_changed_cb, &snapdev, DS_FIND_SNAPSHOTS | DS_FIND_CHILDREN); /* caller should continue to modify snapdev property */ return (-1); }
/* * Create minors for the specified dataset, including children and snapshots. * Pay attention to the 'snapdev' property and iterate over the snapshots * only if they are 'visible'. This approach allows one to assure that the * snapshot metadata is read from disk only if it is needed. * * The name can represent a dataset to be recursively scanned for zvols and * their snapshots, or a single zvol snapshot. If the name represents a * dataset, the scan is performed in two nested stages: * - scan the dataset for zvols, and * - for each zvol, create a minor node, then check if the zvol's snapshots * are 'visible', and only then iterate over the snapshots if needed * * If the name represents a snapshot, a check is perfromed if the snapshot is * 'visible' (which also verifies that the parent is a zvol), and if so, * a minor node for that snapshot is created. */ static int zvol_create_minors_impl(const char *name) { int error = 0; fstrans_cookie_t cookie; char *atp, *parent; if (zvol_inhibit_dev) return (0); parent = kmem_alloc(MAXPATHLEN, KM_SLEEP); (void) strlcpy(parent, name, MAXPATHLEN); if ((atp = strrchr(parent, '@')) != NULL) { uint64_t snapdev; *atp = '\0'; error = dsl_prop_get_integer(parent, "snapdev", &snapdev, NULL); if (error == 0 && snapdev == ZFS_SNAPDEV_VISIBLE) error = zvol_create_minor_impl(name); } else { cookie = spl_fstrans_mark(); error = dmu_objset_find(parent, zvol_create_minors_cb, NULL, DS_FIND_CHILDREN); spl_fstrans_unmark(cookie); } kmem_free(parent, MAXPATHLEN); return (SET_ERROR(error)); }
int dmu_objset_snapshot(char *fsname, char *snapname, boolean_t recursive) { dsl_sync_task_t *dst; struct osnode *osn; struct snaparg sn = { 0 }; spa_t *spa; int err; (void) strcpy(sn.failed, fsname); err = spa_open(fsname, &spa, FTAG); if (err) return (err); sn.dstg = dsl_sync_task_group_create(spa_get_dsl(spa)); sn.snapname = snapname; list_create(&sn.objsets, sizeof (struct osnode), offsetof(struct osnode, node)); if (recursive) { sn.checkperms = B_TRUE; err = dmu_objset_find(fsname, dmu_objset_snapshot_one, &sn, DS_FIND_CHILDREN); } else { sn.checkperms = B_FALSE; err = dmu_objset_snapshot_one(fsname, &sn); } if (err) goto out; err = dsl_sync_task_group_wait(sn.dstg); for (dst = list_head(&sn.dstg->dstg_tasks); dst; dst = list_next(&sn.dstg->dstg_tasks, dst)) { dsl_dataset_t *ds = dst->dst_arg1; if (dst->dst_err) dsl_dataset_name(ds, sn.failed); } out: while (osn = list_head(&sn.objsets)) { list_remove(&sn.objsets, osn); zil_resume(dmu_objset_zil(osn->os)); dmu_objset_close(osn->os); kmem_free(osn, sizeof (struct osnode)); } list_destroy(&sn.objsets); if (err) (void) strcpy(fsname, sn.failed); dsl_sync_task_group_destroy(sn.dstg); spa_close(spa, FTAG); return (err); }
/* * Create minors for specified dataset including children and snapshots. */ int zvol_create_minors(const char *name) { int error = 0; if (!zvol_inhibit_dev) error = dmu_objset_find((char *)name, zvol_create_minors_cb, NULL, DS_FIND_CHILDREN | DS_FIND_SNAPSHOTS); return (SET_ERROR(error)); }
static void zvol_set_snapdev_impl(char *name, uint64_t snapdev) { zvol_snapdev_cb_arg_t arg = {snapdev}; fstrans_cookie_t cookie = spl_fstrans_mark(); /* * The zvol_set_snapdev_sync() sets snapdev appropriately * in the dataset hierarchy. Here, we only scan snapshots. */ dmu_objset_find(name, zvol_set_snapdev_cb, &arg, DS_FIND_SNAPSHOTS); spl_fstrans_unmark(cookie); }
int dmu_objset_snapshot(char *fsname, char *snapname, nvlist_t *props, boolean_t recursive) { dsl_sync_task_t *dst; struct snaparg *sn; spa_t *spa; int err; sn = kmem_alloc(sizeof (struct snaparg), KM_SLEEP); (void) strcpy(sn->failed, fsname); err = spa_open(fsname, &spa, FTAG); if (err) { kmem_free(sn, sizeof (struct snaparg)); return (err); } sn->dstg = dsl_sync_task_group_create(spa_get_dsl(spa)); sn->snapname = snapname; sn->props = props; if (recursive) { sn->checkperms = B_TRUE; err = dmu_objset_find(fsname, dmu_objset_snapshot_one, sn, DS_FIND_CHILDREN); } else { sn->checkperms = B_FALSE; err = dmu_objset_snapshot_one(fsname, sn); } if (err == 0) err = dsl_sync_task_group_wait(sn->dstg); for (dst = list_head(&sn->dstg->dstg_tasks); dst; dst = list_next(&sn->dstg->dstg_tasks, dst)) { objset_t *os = dst->dst_arg1; dsl_dataset_t *ds = os->os->os_dsl_dataset; if (dst->dst_err) dsl_dataset_name(ds, sn->failed); zil_resume(dmu_objset_zil(os)); dmu_objset_close(os); } if (err) (void) strcpy(fsname, sn->failed); dsl_sync_task_group_destroy(sn->dstg); spa_close(spa, FTAG); kmem_free(sn, sizeof (struct snaparg)); return (err); }
static zfs_handle_t *libzfs_zfs_snapshot_next(libzfs_handle_t *p_libzfshd, const char *psz_zfs, char *psz_buffer, size_t i_buffer, uint64_t *p_cookie, const char **ppsz_error) { objset_t *p_os; size_t i_zfs_len = strlen(psz_zfs); int i_error; /* Check the size of the zfs name */ if(i_zfs_len >= i_buffer) { *ppsz_error = "ZFS name too long to handle snapshots"; return NULL; } if(*p_cookie == 0) dmu_objset_find(psz_zfs, dmu_objset_prefetch, NULL, DS_FIND_SNAPSHOTS); top: if((i_error = dmu_objset_hold(psz_zfs, FTAG, &p_os))) { *ppsz_error = "Unable to hold the zfs filesystem"; return NULL; } snprintf(psz_buffer, i_buffer, "%s@", psz_zfs); if((i_error = dmu_snapshot_list_next(p_os, i_buffer - i_zfs_len - 1, psz_buffer + i_zfs_len + 1, NULL, p_cookie, NULL))) *ppsz_error = "Unable to get the next snapshot"; dmu_objset_rele(p_os, FTAG); zfs_handle_t *p_zfs_snap = NULL; if(i_error == 0) { i_error = dmu_objset_hold(psz_buffer, FTAG, &p_os); if(i_error == ENOENT) goto top; if(!(p_zfs_snap = libzfs_make_dataset_handle(p_libzfshd, psz_buffer))) *ppsz_error = "Unable to create a zfs handle for the snapshot"; dmu_objset_rele(p_os, FTAG); } return p_zfs_snap; }
/* * Mask errors to continue dmu_objset_find() traversal */ static int zvol_create_minors_cb(const char *dsname, void *arg) { uint64_t snapdev; int error; ASSERT0(MUTEX_HELD(&spa_namespace_lock)); error = dsl_prop_get_integer(dsname, "snapdev", &snapdev, NULL); if (error) return (0); /* * Given the name and the 'snapdev' property, create device minor nodes * with the linkages to zvols/snapshots as needed. * If the name represents a zvol, create a minor node for the zvol, then * check if its snapshots are 'visible', and if so, iterate over the * snapshots and create device minor nodes for those. */ if (strchr(dsname, '@') == 0) { /* create minor for the 'dsname' explicitly */ error = zvol_create_minor_impl(dsname); if ((error == 0 || error == EEXIST) && (snapdev == ZFS_SNAPDEV_VISIBLE)) { fstrans_cookie_t cookie = spl_fstrans_mark(); /* * traverse snapshots only, do not traverse children, * and skip the 'dsname' */ error = dmu_objset_find((char *)dsname, zvol_create_snap_minor_cb, (void *)dsname, DS_FIND_SNAPSHOTS); spl_fstrans_unmark(cookie); } } else { dprintf("zvol_create_minors_cb(): %s is not a zvol name\n", dsname); } return (0); }
int dsl_crypto_key_change(char *dsname, zcrypt_key_t *newkey, nvlist_t *props) { struct wkey_change_arg *ca; struct kcnode *kcn; dsl_dataset_t *ds; dsl_props_arg_t pa; spa_t *spa; int err; //dsl_sync_task_group_t *dstg; zcrypt_key_t *oldkey; dsl_pool_t *dp; ASSERT(newkey != NULL); ASSERT(dsname != NULL); err = dsl_pool_hold(dsname, FTAG, &dp); if (err != 0) return (err); if ((err = dsl_dataset_hold(dp, dsname, FTAG, &ds)) != 0) { dsl_pool_rele(dp, FTAG); return (err); } /* * Take the spa lock here so that new datasets can't get * created below us while we are doing a wrapping key change. * This is to avoid them being created with the wrong inherited * wrapping key. */ err = spa_open(dsname, &spa, FTAG); if (err) return (err); oldkey = zcrypt_key_copy(zcrypt_keystore_find_wrappingkey(spa, ds->ds_object)); if (oldkey == NULL) { dsl_dataset_rele(ds, FTAG); dsl_pool_rele(dp, FTAG); spa_close(spa, FTAG); return (ENOENT); } ca = kmem_alloc(sizeof (struct wkey_change_arg), KM_SLEEP); ca->ca_new_key = newkey; ca->ca_old_key = oldkey; ca->ca_parent = dsname; ca->ca_props = props; list_create(&ca->ca_nodes, sizeof (struct kcnode), offsetof(struct kcnode, kc_node)); zcrypt_key_hold(ca->ca_old_key, FTAG); zcrypt_key_hold(ca->ca_new_key, FTAG); //ca->ca_ds = dsl_sync_task_group_create(spa_get_dsl(spa)); err = dmu_objset_find(dsname, dsl_crypto_key_change_find, ca, DS_FIND_CHILDREN); /* * If this is the "top" dataset in this keychange it gets * the keysource and salt properties updated. */ pa.pa_props = props; pa.pa_source = ZPROP_SRC_LOCAL; //pa.pa_flags = 0; //pa.pa_zone = curzone; //dsl_sync_task_create(ca->ca_dstg, NULL, dsl_props_set_sync, ds, &pa, 2); dsl_props_set(dsname, ZPROP_SRC_LOCAL, props); //if (err == 0) //err = dsl_sync_task_group_wait(dstg); while ((kcn = list_head(&ca->ca_nodes))) { list_remove(&ca->ca_nodes, kcn); dsl_dataset_rele(kcn->kc_ds, kcn); kmem_free(kcn, sizeof (struct kcnode)); } //dsl_sync_task_group_destroy(ca->ca_dstg); /* * We are finished so release and free both the old and new keys. * We can free even the new key because everyone got a copy of it * not a reference to this one. */ zcrypt_key_release(ca->ca_old_key, FTAG); zcrypt_key_free(ca->ca_old_key); zcrypt_key_release(ca->ca_new_key, FTAG); zcrypt_key_free(ca->ca_new_key); kmem_free(ca, sizeof (struct wkey_change_arg)); dsl_dataset_rele(ds, FTAG); dsl_pool_rele(dp, FTAG); spa_close(spa, FTAG); return (err); }