static int lzc_ioctl(zfs_ioc_t ioc, const char *name, nvlist_t *source, nvlist_t **resultp) { zfs_cmd_t zc = {"\0"}; int error = 0; char *packed = NULL; size_t size = 0; ASSERT3S(g_refcount, >, 0); VERIFY3S(g_fd, !=, -1); if (name != NULL) (void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name)); if (source != NULL) { packed = fnvlist_pack(source, &size); zc.zc_nvlist_src = (uint64_t)(uintptr_t)packed; zc.zc_nvlist_src_size = size; } if (resultp != NULL) { *resultp = NULL; zc.zc_nvlist_dst_size = MAX(size * 2, 128 * 1024); zc.zc_nvlist_dst = (uint64_t)(uintptr_t) malloc(zc.zc_nvlist_dst_size); if (zc.zc_nvlist_dst == (uint64_t)0) { error = ENOMEM; goto out; } } while (ioctl(g_fd, ioc, &zc) != 0) { if (errno == ENOMEM && resultp != NULL) { free((void *)(uintptr_t)zc.zc_nvlist_dst); zc.zc_nvlist_dst_size *= 2; zc.zc_nvlist_dst = (uint64_t)(uintptr_t) malloc(zc.zc_nvlist_dst_size); if (zc.zc_nvlist_dst == (uint64_t)0) { error = ENOMEM; goto out; } } else { error = errno; break; } } if (zc.zc_nvlist_dst_filled) { *resultp = fnvlist_unpack((void *)(uintptr_t)zc.zc_nvlist_dst, zc.zc_nvlist_dst_size); } out: if (packed != NULL) fnvlist_pack_free(packed, size); free((void *)(uintptr_t)zc.zc_nvlist_dst); return (error); }
/* * run a zfs ioctl command, verify expected results and log failures */ static void lzc_ioctl_run(zfs_ioc_t ioc, const char *name, nvlist_t *innvl, int expected) { zfs_cmd_t zc = {"\0"}; char *packed = NULL; const char *variant; size_t size = 0; int error = 0; switch (expected) { case ZFS_ERR_IOC_ARG_UNAVAIL: variant = "unsupported input"; break; case ZFS_ERR_IOC_ARG_REQUIRED: variant = "missing input"; break; case ZFS_ERR_IOC_ARG_BADTYPE: variant = "invalid input type"; break; default: variant = "valid input"; break; } packed = fnvlist_pack(innvl, &size); (void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name)); zc.zc_name[sizeof (zc.zc_name) - 1] = '\0'; zc.zc_nvlist_src = (uint64_t)(uintptr_t)packed; zc.zc_nvlist_src_size = size; zc.zc_nvlist_dst_size = MAX(size * 2, 128 * 1024); zc.zc_nvlist_dst = (uint64_t)(uintptr_t)malloc(zc.zc_nvlist_dst_size); if (ioctl(zfs_fd, ioc, &zc) != 0) error = errno; if (error != expected) { unexpected_failures = B_TRUE; (void) fprintf(stderr, "%s: Unexpected result with %s, " "error %d (expecting %d)\n", active_test, variant, error, expected); } fnvlist_pack_free(packed, size); free((void *)(uintptr_t)zc.zc_nvlist_dst); }
static int pool_active(void *unused, const char *name, uint64_t guid, boolean_t *isactive) { zfs_cmd_t *zcp; nvlist_t *innvl; char *packed = NULL; size_t size = 0; int fd, ret; /* * Use ZFS_IOC_POOL_SYNC to confirm if a pool is active */ fd = open("/dev/zfs", O_RDWR); if (fd < 0) return (-1); zcp = umem_zalloc(sizeof (zfs_cmd_t), UMEM_NOFAIL); innvl = fnvlist_alloc(); fnvlist_add_boolean_value(innvl, "force", B_FALSE); (void) strlcpy(zcp->zc_name, name, sizeof (zcp->zc_name)); packed = fnvlist_pack(innvl, &size); zcp->zc_nvlist_src = (uint64_t)(uintptr_t)packed; zcp->zc_nvlist_src_size = size; ret = ioctl(fd, ZFS_IOC_POOL_SYNC, zcp); fnvlist_pack_free(packed, size); free((void *)(uintptr_t)zcp->zc_nvlist_dst); nvlist_free(innvl); umem_free(zcp, sizeof (zfs_cmd_t)); (void) close(fd); *isactive = (ret == 0); return (0); }
/* * The simplest receive case: receive from the specified fd, creating the * specified snapshot. Apply the specified properties a "received" properties * (which can be overridden by locally-set properties). If the stream is a * clone, its origin snapshot must be specified by 'origin'. The 'force' * flag will cause the target filesystem to be rolled back or destroyed if * necessary to receive. * * Return 0 on success or an errno on failure. * * Note: this interface does not work on dedup'd streams * (those with DMU_BACKUP_FEATURE_DEDUP). */ int lzc_receive(const char *snapname, nvlist_t *props, const char *origin, boolean_t force, int fd) { /* * The receive ioctl is still legacy, so we need to construct our own * zfs_cmd_t rather than using zfsc_ioctl(). */ zfs_cmd_t zc = { 0 }; char *atp; char *packed = NULL; size_t size; dmu_replay_record_t drr; int error; ASSERT3S(g_refcount, >, 0); /* zc_name is name of containing filesystem */ (void) strlcpy(zc.zc_name, snapname, sizeof (zc.zc_name)); atp = strchr(zc.zc_name, '@'); if (atp == NULL) return (EINVAL); *atp = '\0'; /* if the fs does not exist, try its parent. */ if (!lzc_exists(zc.zc_name)) { char *slashp = strrchr(zc.zc_name, '/'); if (slashp == NULL) return (ENOENT); *slashp = '\0'; } /* zc_value is full name of the snapshot to create */ (void) strlcpy(zc.zc_value, snapname, sizeof (zc.zc_value)); if (props != NULL) { /* zc_nvlist_src is props to set */ packed = fnvlist_pack(props, &size); zc.zc_nvlist_src = (uint64_t)(uintptr_t)packed; zc.zc_nvlist_src_size = size; } /* zc_string is name of clone origin (if DRR_FLAG_CLONE) */ if (origin != NULL) (void) strlcpy(zc.zc_string, origin, sizeof (zc.zc_string)); /* zc_begin_record is non-byteswapped BEGIN record */ error = recv_read(fd, &drr, sizeof (drr)); if (error != 0) goto out; zc.zc_begin_record = drr.drr_u.drr_begin; /* zc_cookie is fd to read from */ zc.zc_cookie = fd; /* zc guid is force flag */ zc.zc_guid = force; /* zc_cleanup_fd is unused */ zc.zc_cleanup_fd = -1; error = ioctl(g_fd, ZFS_IOC_RECV, &zc); if (error != 0) error = errno; out: if (packed != NULL) fnvlist_pack_free(packed, size); free((void*)(uintptr_t)zc.zc_nvlist_dst); return (error); }
/*ARGSUSED*/ static void spa_history_log_sync(void *arg, dmu_tx_t *tx) { nvlist_t *nvl = arg; spa_t *spa = dmu_tx_pool(tx)->dp_spa; objset_t *mos = spa->spa_meta_objset; dmu_buf_t *dbp; spa_history_phys_t *shpp; size_t reclen; uint64_t le_len; char *record_packed = NULL; int ret; /* * If we have an older pool that doesn't have a command * history object, create it now. */ mutex_enter(&spa->spa_history_lock); if (!spa->spa_history) spa_history_create_obj(spa, tx); mutex_exit(&spa->spa_history_lock); /* * Get the offset of where we need to write via the bonus buffer. * Update the offset when the write completes. */ VERIFY0(dmu_bonus_hold(mos, spa->spa_history, FTAG, &dbp)); shpp = dbp->db_data; dmu_buf_will_dirty(dbp, tx); #ifdef ZFS_DEBUG { dmu_object_info_t doi; dmu_object_info_from_db(dbp, &doi); ASSERT3U(doi.doi_bonus_type, ==, DMU_OT_SPA_HISTORY_OFFSETS); } #endif fnvlist_add_uint64(nvl, ZPOOL_HIST_TIME, gethrestime_sec()); #ifdef _KERNEL fnvlist_add_string(nvl, ZPOOL_HIST_HOST, utsname.nodename); #endif if (nvlist_exists(nvl, ZPOOL_HIST_CMD)) { zfs_dbgmsg("command: %s", fnvlist_lookup_string(nvl, ZPOOL_HIST_CMD)); } else if (nvlist_exists(nvl, ZPOOL_HIST_INT_NAME)) { if (nvlist_exists(nvl, ZPOOL_HIST_DSNAME)) { zfs_dbgmsg("txg %lld %s %s (id %llu) %s", fnvlist_lookup_uint64(nvl, ZPOOL_HIST_TXG), fnvlist_lookup_string(nvl, ZPOOL_HIST_INT_NAME), fnvlist_lookup_string(nvl, ZPOOL_HIST_DSNAME), fnvlist_lookup_uint64(nvl, ZPOOL_HIST_DSID), fnvlist_lookup_string(nvl, ZPOOL_HIST_INT_STR)); } else { zfs_dbgmsg("txg %lld %s %s", fnvlist_lookup_uint64(nvl, ZPOOL_HIST_TXG), fnvlist_lookup_string(nvl, ZPOOL_HIST_INT_NAME), fnvlist_lookup_string(nvl, ZPOOL_HIST_INT_STR)); } } else if (nvlist_exists(nvl, ZPOOL_HIST_IOCTL)) { zfs_dbgmsg("ioctl %s", fnvlist_lookup_string(nvl, ZPOOL_HIST_IOCTL)); } record_packed = fnvlist_pack(nvl, &reclen); mutex_enter(&spa->spa_history_lock); /* write out the packed length as little endian */ le_len = LE_64((uint64_t)reclen); ret = spa_history_write(spa, &le_len, sizeof (le_len), shpp, tx); if (!ret) ret = spa_history_write(spa, record_packed, reclen, shpp, tx); /* The first command is the create, which we keep forever */ if (ret == 0 && shpp->sh_pool_create_len == 0 && nvlist_exists(nvl, ZPOOL_HIST_CMD)) { shpp->sh_pool_create_len = shpp->sh_bof = shpp->sh_eof; } mutex_exit(&spa->spa_history_lock); fnvlist_pack_free(record_packed, reclen); dmu_buf_rele(dbp, FTAG); fnvlist_free(nvl); }
static int lzc_ioctl(zfs_ioc_t ioc, const char *name, nvlist_t *source, nvlist_t **resultp) { zfs_cmd_t zc = {"\0"}; int error = 0; int ioctl_err = 0; char *packed; size_t size; ASSERT3S(g_refcount, >, 0); (void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name)); packed = fnvlist_pack(source, &size); zc.zc_nvlist_src = (uint64_t)(uintptr_t)packed; zc.zc_nvlist_src_size = size; if (resultp != NULL) { *resultp = NULL; zc.zc_nvlist_dst_size = MAX(size * 2, 128 * 1024); zc.zc_nvlist_dst = (uint64_t)(uintptr_t) malloc(zc.zc_nvlist_dst_size); if (zc.zc_nvlist_dst == (uint64_t)0) { error = ENOMEM; goto out; } } while ((ioctl_err = ioctl(g_fd, ioc, &zc)) != 0 || zc.zc_ioc_error != 0) { if (zc.zc_ioc_error != 0) { errno = zc.zc_ioc_error; } else if (ioctl_err != -1) { dprintf("ioctl should return 0, or both return -1 and set errno, " "but instead : ioctl_err %d : errno %d\n", ioctl_err, errno); errno = ioctl_err; } else if (ioctl_err == -1 && errno == 0) { dprintf("ioctl returned -1, so errno should have been nonzero.\n"); errno = -1; } if (errno == ENOMEM && resultp != NULL) { free((void *)(uintptr_t)zc.zc_nvlist_dst); zc.zc_nvlist_dst_size *= 2; zc.zc_nvlist_dst = (uint64_t)(uintptr_t) malloc(zc.zc_nvlist_dst_size); if (zc.zc_nvlist_dst == (uint64_t)0) { error = ENOMEM; goto out; } } else { error = errno; break; } } if (zc.zc_nvlist_dst_filled) { *resultp = fnvlist_unpack((void *)(uintptr_t)zc.zc_nvlist_dst, zc.zc_nvlist_dst_size); } out: fnvlist_pack_free(packed, size); free((void *)(uintptr_t)zc.zc_nvlist_dst); return (error); }
static int spa_config_write(spa_config_dirent_t *dp, nvlist_t *nvl) { size_t buflen; char *buf; vnode_t *vp; int oflags = FWRITE | FTRUNC | FCREAT | FOFFMAX; char *temp; int err; /* * If the nvlist is empty (NULL), then remove the old cachefile. */ if (nvl == NULL) { err = vn_remove(dp->scd_path, UIO_SYSSPACE, RMFILE); return (err); } /* * Pack the configuration into a buffer. */ buf = fnvlist_pack(nvl, &buflen); temp = kmem_zalloc(MAXPATHLEN, KM_SLEEP); #if defined(__linux__) && defined(_KERNEL) /* * Write the configuration to disk. Due to the complexity involved * in performing a rename from within the kernel the file is truncated * and overwritten in place. In the event of an error the file is * unlinked to make sure we always have a consistent view of the data. */ err = vn_open(dp->scd_path, UIO_SYSSPACE, oflags, 0644, &vp, 0, 0); if (err == 0) { err = vn_rdwr(UIO_WRITE, vp, buf, buflen, 0, UIO_SYSSPACE, 0, RLIM64_INFINITY, kcred, NULL); if (err == 0) err = VOP_FSYNC(vp, FSYNC, kcred, NULL); (void) VOP_CLOSE(vp, oflags, 1, 0, kcred, NULL); if (err) (void) vn_remove(dp->scd_path, UIO_SYSSPACE, RMFILE); } #else /* * Write the configuration to disk. We need to do the traditional * 'write to temporary file, sync, move over original' to make sure we * always have a consistent view of the data. */ (void) snprintf(temp, MAXPATHLEN, "%s.tmp", dp->scd_path); err = vn_open(temp, UIO_SYSSPACE, oflags, 0644, &vp, CRCREAT, 0); if (err == 0) { err = vn_rdwr(UIO_WRITE, vp, buf, buflen, 0, UIO_SYSSPACE, 0, RLIM64_INFINITY, kcred, NULL); if (err == 0) err = VOP_FSYNC(vp, FSYNC, kcred, NULL); if (err == 0) err = vn_rename(temp, dp->scd_path, UIO_SYSSPACE); (void) VOP_CLOSE(vp, oflags, 1, 0, kcred, NULL); } (void) vn_remove(temp, UIO_SYSSPACE, RMFILE); #endif fnvlist_pack_free(buf, buflen); kmem_free(temp, MAXPATHLEN); return (err); }
/* * Linux adds ZFS_IOC_RECV_NEW for resumable and raw streams and preserves the * legacy ZFS_IOC_RECV user/kernel interface. The new interface supports all * stream options but is currently only used for resumable streams. This way * updated user space utilities will interoperate with older kernel modules. * * Non-Linux OpenZFS platforms have opted to modify the legacy interface. */ static int recv_impl(const char *snapname, nvlist_t *recvdprops, nvlist_t *localprops, const char *origin, boolean_t force, boolean_t resumable, boolean_t raw, int input_fd, const dmu_replay_record_t *begin_record, int cleanup_fd, uint64_t *read_bytes, uint64_t *errflags, uint64_t *action_handle, nvlist_t **errors) { dmu_replay_record_t drr; char fsname[MAXPATHLEN]; char *atp; int error; ASSERT3S(g_refcount, >, 0); VERIFY3S(g_fd, !=, -1); /* Set 'fsname' to the name of containing filesystem */ (void) strlcpy(fsname, snapname, sizeof (fsname)); atp = strchr(fsname, '@'); if (atp == NULL) return (EINVAL); *atp = '\0'; /* If the fs does not exist, try its parent. */ if (!lzc_exists(fsname)) { char *slashp = strrchr(fsname, '/'); if (slashp == NULL) return (ENOENT); *slashp = '\0'; } /* * The begin_record is normally a non-byteswapped BEGIN record. * For resumable streams it may be set to any non-byteswapped * dmu_replay_record_t. */ if (begin_record == NULL) { error = recv_read(input_fd, &drr, sizeof (drr)); if (error != 0) return (error); } else { drr = *begin_record; } if (resumable || raw) { nvlist_t *outnvl = NULL; nvlist_t *innvl = fnvlist_alloc(); fnvlist_add_string(innvl, "snapname", snapname); if (recvdprops != NULL) fnvlist_add_nvlist(innvl, "props", recvdprops); if (localprops != NULL) fnvlist_add_nvlist(innvl, "localprops", localprops); if (origin != NULL && strlen(origin)) fnvlist_add_string(innvl, "origin", origin); fnvlist_add_byte_array(innvl, "begin_record", (uchar_t *)&drr, sizeof (drr)); fnvlist_add_int32(innvl, "input_fd", input_fd); if (force) fnvlist_add_boolean(innvl, "force"); if (resumable) fnvlist_add_boolean(innvl, "resumable"); if (cleanup_fd >= 0) fnvlist_add_int32(innvl, "cleanup_fd", cleanup_fd); if (action_handle != NULL) fnvlist_add_uint64(innvl, "action_handle", *action_handle); error = lzc_ioctl(ZFS_IOC_RECV_NEW, fsname, innvl, &outnvl); if (error == 0 && read_bytes != NULL) error = nvlist_lookup_uint64(outnvl, "read_bytes", read_bytes); if (error == 0 && errflags != NULL) error = nvlist_lookup_uint64(outnvl, "error_flags", errflags); if (error == 0 && action_handle != NULL) error = nvlist_lookup_uint64(outnvl, "action_handle", action_handle); if (error == 0 && errors != NULL) { nvlist_t *nvl; error = nvlist_lookup_nvlist(outnvl, "errors", &nvl); if (error == 0) *errors = fnvlist_dup(nvl); } fnvlist_free(innvl); fnvlist_free(outnvl); } else { zfs_cmd_t zc = {"\0"}; char *packed = NULL; size_t size; ASSERT3S(g_refcount, >, 0); (void) strlcpy(zc.zc_name, fsname, sizeof (zc.zc_value)); (void) strlcpy(zc.zc_value, snapname, sizeof (zc.zc_value)); if (recvdprops != NULL) { packed = fnvlist_pack(recvdprops, &size); zc.zc_nvlist_src = (uint64_t)(uintptr_t)packed; zc.zc_nvlist_src_size = size; } if (localprops != NULL) { packed = fnvlist_pack(localprops, &size); zc.zc_nvlist_conf = (uint64_t)(uintptr_t)packed; zc.zc_nvlist_conf_size = size; } if (origin != NULL) (void) strlcpy(zc.zc_string, origin, sizeof (zc.zc_string)); ASSERT3S(drr.drr_type, ==, DRR_BEGIN); zc.zc_begin_record = drr.drr_u.drr_begin; zc.zc_guid = force; zc.zc_cookie = input_fd; zc.zc_cleanup_fd = -1; zc.zc_action_handle = 0; if (cleanup_fd >= 0) zc.zc_cleanup_fd = cleanup_fd; if (action_handle != NULL) zc.zc_action_handle = *action_handle; zc.zc_nvlist_dst_size = 128 * 1024; zc.zc_nvlist_dst = (uint64_t)(uintptr_t) malloc(zc.zc_nvlist_dst_size); error = ioctl(g_fd, ZFS_IOC_RECV, &zc); if (error != 0) { error = errno; } else { if (read_bytes != NULL) *read_bytes = zc.zc_cookie; if (errflags != NULL) *errflags = zc.zc_obj; if (action_handle != NULL) *action_handle = zc.zc_action_handle; if (errors != NULL) VERIFY0(nvlist_unpack( (void *)(uintptr_t)zc.zc_nvlist_dst, zc.zc_nvlist_dst_size, errors, KM_SLEEP)); } if (packed != NULL) fnvlist_pack_free(packed, size); free((void *)(uintptr_t)zc.zc_nvlist_dst); } return (error); }
static int lzc_ioctl(zfs_ioc_t ioc, const char *name, nvlist_t *source, nvlist_t **resultp) { zfs_cmd_t zc = { 0 }; int error = 0; char *packed; #ifdef __FreeBSD__ nvlist_t *oldsource; #endif size_t size; ASSERT3S(g_refcount, >, 0); (void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name)); #ifdef __FreeBSD__ if (zfs_ioctl_version == ZFS_IOCVER_UNDEF) zfs_ioctl_version = get_zfs_ioctl_version(); if (zfs_ioctl_version < ZFS_IOCVER_LZC) { oldsource = source; error = lzc_compat_pre(&zc, &ioc, &source); if (error) return (error); } #endif packed = fnvlist_pack(source, &size); zc.zc_nvlist_src = (uint64_t)(uintptr_t)packed; zc.zc_nvlist_src_size = size; if (resultp != NULL) { *resultp = NULL; zc.zc_nvlist_dst_size = MAX(size * 2, 128 * 1024); zc.zc_nvlist_dst = (uint64_t)(uintptr_t) malloc(zc.zc_nvlist_dst_size); #ifdef illumos if (zc.zc_nvlist_dst == NULL) { #else if (zc.zc_nvlist_dst == 0) { #endif error = ENOMEM; goto out; } } while (ioctl(g_fd, ioc, &zc) != 0) { if (errno == ENOMEM && resultp != NULL) { free((void *)(uintptr_t)zc.zc_nvlist_dst); zc.zc_nvlist_dst_size *= 2; zc.zc_nvlist_dst = (uint64_t)(uintptr_t) malloc(zc.zc_nvlist_dst_size); #ifdef illumos if (zc.zc_nvlist_dst == NULL) { #else if (zc.zc_nvlist_dst == 0) { #endif error = ENOMEM; goto out; } } else { error = errno; break; } } #ifdef __FreeBSD__ if (zfs_ioctl_version < ZFS_IOCVER_LZC) lzc_compat_post(&zc, ioc); #endif if (zc.zc_nvlist_dst_filled) { *resultp = fnvlist_unpack((void *)(uintptr_t)zc.zc_nvlist_dst, zc.zc_nvlist_dst_size); } #ifdef __FreeBSD__ if (zfs_ioctl_version < ZFS_IOCVER_LZC) lzc_compat_outnvl(&zc, ioc, resultp); #endif out: #ifdef __FreeBSD__ if (zfs_ioctl_version < ZFS_IOCVER_LZC) { if (source != oldsource) nvlist_free(source); source = oldsource; } #endif fnvlist_pack_free(packed, size); free((void *)(uintptr_t)zc.zc_nvlist_dst); return (error); } int lzc_create(const char *fsname, enum lzc_dataset_type type, nvlist_t *props) { int error; nvlist_t *args = fnvlist_alloc(); fnvlist_add_int32(args, "type", (dmu_objset_type_t)type); if (props != NULL) fnvlist_add_nvlist(args, "props", props); error = lzc_ioctl(ZFS_IOC_CREATE, fsname, args, NULL); nvlist_free(args); return (error); }
static void spa_config_write(spa_config_dirent_t *dp, nvlist_t *nvl) { size_t buflen; char *buf; vnode_t *vp; int oflags = FWRITE | FTRUNC | FCREAT | FOFFMAX; #ifdef __linux__ int error; #endif char *temp; /* * If the nvlist is empty (NULL), then remove the old cachefile. */ if (nvl == NULL) { #ifdef __APPLE__ /* released in caller due to spa */ #else (void) vn_remove(dp->scd_path, UIO_SYSSPACE, RMFILE); #endif return; } /* * Pack the configuration into a buffer. */ buf = fnvlist_pack(nvl, &buflen); temp = kmem_zalloc(MAXPATHLEN, KM_SLEEP); /* * Write the configuration to disk. We need to do the traditional * 'write to temporary file, sync, move over original' to make sure we * always have a consistent view of the data. */ (void) snprintf(temp, MAXPATHLEN, "%s.tmp", dp->scd_path); if (vn_open(temp, UIO_SYSSPACE, oflags, 0644, &vp, CRCREAT, 0) == 0) { if (vn_rdwr(UIO_WRITE, vp, buf, buflen, 0, UIO_SYSSPACE, 0, RLIM64_INFINITY, kcred, NULL) == 0 && VOP_FSYNC(vp, FSYNC, kcred, NULL) == 0) { #if defined (__APPLE__) && defined (_KERNEL) /* kernel renamed in caller due to 'spa' - userland for ztest*/ #else (void) vn_rename(temp, dp->scd_path, UIO_SYSSPACE); #endif } (void) VOP_CLOSE(vp, oflags, 1, 0, kcred, NULL); } #if defined (__APPLE__) && defined (_KERNEL) /* Not needed if rename is successful */ #else (void) vn_remove(temp, UIO_SYSSPACE, RMFILE); #endif fnvlist_pack_free(buf, buflen); kmem_free(temp, MAXPATHLEN); }
static int lzc_ioctl(zfs_ioc_t ioc, const char *name, nvlist_t *source, nvlist_t **resultp) { zfs_cmd_t zc = {"\0"}; int error = 0; char *packed = NULL; size_t size = 0; ASSERT3S(g_refcount, >, 0); VERIFY3S(g_fd, !=, -1); if (name != NULL) (void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name)); if (source != NULL) { packed = fnvlist_pack(source, &size); zc.zc_nvlist_src = (uint64_t)(uintptr_t)packed; zc.zc_nvlist_src_size = size; } if (resultp != NULL) { *resultp = NULL; if (ioc == ZFS_IOC_CHANNEL_PROGRAM) { zc.zc_nvlist_dst_size = fnvlist_lookup_uint64(source, ZCP_ARG_MEMLIMIT); } else { zc.zc_nvlist_dst_size = MAX(size * 2, 128 * 1024); } zc.zc_nvlist_dst = (uint64_t)(uintptr_t) malloc(zc.zc_nvlist_dst_size); if (zc.zc_nvlist_dst == (uint64_t)0) { error = ENOMEM; goto out; } } while (ioctl(g_fd, ioc, &zc) != 0) { /* * If ioctl exited with ENOMEM, we retry the ioctl after * increasing the size of the destination nvlist. * * Channel programs that exit with ENOMEM ran over the * lua memory sandbox; they should not be retried. */ if (errno == ENOMEM && resultp != NULL && ioc != ZFS_IOC_CHANNEL_PROGRAM) { free((void *)(uintptr_t)zc.zc_nvlist_dst); zc.zc_nvlist_dst_size *= 2; zc.zc_nvlist_dst = (uint64_t)(uintptr_t) malloc(zc.zc_nvlist_dst_size); if (zc.zc_nvlist_dst == (uint64_t)0) { error = ENOMEM; goto out; } } else { error = errno; break; } } if (zc.zc_nvlist_dst_filled) { *resultp = fnvlist_unpack((void *)(uintptr_t)zc.zc_nvlist_dst, zc.zc_nvlist_dst_size); } out: if (packed != NULL) fnvlist_pack_free(packed, size); free((void *)(uintptr_t)zc.zc_nvlist_dst); return (error); }