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. */ VERIFY(nvlist_size(nvl, &buflen, NV_ENCODE_XDR) == 0); buf = kmem_alloc(buflen, KM_SLEEP); temp = kmem_zalloc(MAXPATHLEN, KM_SLEEP); VERIFY(nvlist_pack(nvl, &buf, &buflen, NV_ENCODE_XDR, KM_SLEEP) == 0); /* * 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); kmem_free(buf, buflen); kmem_free(temp, MAXPATHLEN); return (err); }
static int kfrename(char *oldname, char *newname) { int rval; ASSERT(modrootloaded); KFDEBUG((CE_CONT, "renaming %s to %s\n", oldname, newname)); if ((rval = vn_rename(oldname, newname, UIO_SYSSPACE)) != 0) { KFDEBUG((CE_CONT, "rename %s to %s: %d\n", oldname, newname, rval)); } return (rval); }
/* * Synchronize all pools to disk. This must be called with the namespace lock * held. */ void spa_config_sync(void) { spa_t *spa = NULL; nvlist_t *config; size_t buflen; char *buf; vnode_t *vp; int oflags = FWRITE | FTRUNC | FCREAT | FOFFMAX; char pathname[128]; char pathname2[128]; ASSERT(MUTEX_HELD(&spa_namespace_lock)); VERIFY(nvlist_alloc(&config, NV_UNIQUE_NAME, KM_SLEEP) == 0); /* * Add all known pools to the configuration list, ignoring those with * alternate root paths. */ spa = NULL; while ((spa = spa_next(spa)) != NULL) { mutex_enter(&spa->spa_config_cache_lock); if (spa->spa_config && spa->spa_name && spa->spa_root == NULL) VERIFY(nvlist_add_nvlist(config, spa->spa_name, spa->spa_config) == 0); mutex_exit(&spa->spa_config_cache_lock); } /* * Pack the configuration into a buffer. */ VERIFY(nvlist_size(config, &buflen, NV_ENCODE_XDR) == 0); buf = kmem_alloc(buflen, KM_SLEEP); VERIFY(nvlist_pack(config, &buf, &buflen, NV_ENCODE_XDR, KM_SLEEP) == 0); /* * 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(pathname, sizeof (pathname), "%s/%s", spa_config_dir, ZPOOL_CACHE_TMP); if (vn_open(pathname, UIO_SYSSPACE, oflags, 0644, &vp, CRCREAT, 0) != 0) goto out; if (vn_rdwr(UIO_WRITE, vp, buf, buflen, 0, UIO_SYSSPACE, 0, RLIM64_INFINITY, kcred, NULL) == 0 && VOP_FSYNC(vp, FSYNC, kcred) == 0) { (void) snprintf(pathname2, sizeof (pathname2), "%s/%s", spa_config_dir, ZPOOL_CACHE_FILE); (void) vn_rename(pathname, pathname2, UIO_SYSSPACE); } (void) VOP_CLOSE(vp, oflags, 1, 0, kcred); VN_RELE(vp); out: (void) vn_remove(pathname, UIO_SYSSPACE, RMFILE); spa_config_generation++; kmem_free(buf, buflen); nvlist_free(config); }
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; int error; char *temp; /* * If the nvlist is empty (NULL), then remove the old cachefile. */ if (nvl == NULL) { (void) vn_remove(dp->scd_path, UIO_SYSSPACE, RMFILE); return; } /* * Pack the configuration into a buffer. */ VERIFY(nvlist_size(nvl, &buflen, NV_ENCODE_XDR) == 0); buf = vmem_alloc(buflen, KM_SLEEP); temp = kmem_zalloc(MAXPATHLEN, KM_SLEEP); VERIFY(nvlist_pack(nvl, &buf, &buflen, NV_ENCODE_XDR, KM_SLEEP) == 0); #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. */ error = vn_open(dp->scd_path, UIO_SYSSPACE, oflags, 0644, &vp, 0, 0); if (error == 0) { error = vn_rdwr(UIO_WRITE, vp, buf, buflen, 0, UIO_SYSSPACE, 0, RLIM64_INFINITY, kcred, NULL); if (error == 0) error = VOP_FSYNC(vp, FSYNC, kcred, NULL); (void) VOP_CLOSE(vp, oflags, 1, 0, kcred, NULL); if (error) (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); error = vn_open(temp, UIO_SYSSPACE, oflags, 0644, &vp, CRCREAT, 0); if (error == 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) { (void) 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 vmem_free(buf, buflen); kmem_free(temp, MAXPATHLEN); }
static int splat_vnode_test4(struct file *file, void *arg) { vnode_t *vp; char buf1[32] = "SPL VNode Interface Test File\n"; char buf2[32] = ""; int rc; if ((rc = splat_vnode_unlink_all(file, arg, SPLAT_VNODE_TEST4_NAME))) return rc; if ((rc = vn_open(SPLAT_VNODE_TEST_FILE_RW1, UIO_SYSSPACE, FWRITE | FREAD | FCREAT | FEXCL, 0644, &vp, 0, 0))) { splat_vprint(file, SPLAT_VNODE_TEST4_NAME, "Failed to vn_open test file: %s (%d)\n", SPLAT_VNODE_TEST_FILE_RW1, rc); goto out; } rc = vn_rdwr(UIO_WRITE, vp, buf1, strlen(buf1), 0, UIO_SYSSPACE, 0, RLIM64_INFINITY, 0, NULL); if (rc) { splat_vprint(file, SPLAT_VNODE_TEST4_NAME, "Failed vn_rdwr write of test file: %s (%d)\n", SPLAT_VNODE_TEST_FILE_RW1, rc); goto out2; } VOP_CLOSE(vp, 0, 0, 0, 0, 0); rc = vn_rename(SPLAT_VNODE_TEST_FILE_RW1,SPLAT_VNODE_TEST_FILE_RW2,0); if (rc) { splat_vprint(file, SPLAT_VNODE_TEST4_NAME, "Failed vn_rename " "%s -> %s (%d)\n", SPLAT_VNODE_TEST_FILE_RW1, SPLAT_VNODE_TEST_FILE_RW2, rc); goto out; } if ((rc = vn_open(SPLAT_VNODE_TEST_FILE_RW2, UIO_SYSSPACE, FREAD | FEXCL, 0644, &vp, 0, 0))) { splat_vprint(file, SPLAT_VNODE_TEST4_NAME, "Failed to vn_open test file: %s (%d)\n", SPLAT_VNODE_TEST_FILE_RW2, rc); goto out; } rc = vn_rdwr(UIO_READ, vp, buf2, strlen(buf1), 0, UIO_SYSSPACE, 0, RLIM64_INFINITY, 0, NULL); if (rc) { splat_vprint(file, SPLAT_VNODE_TEST4_NAME, "Failed vn_rdwr read of test file: %s (%d)\n", SPLAT_VNODE_TEST_FILE_RW2, rc); goto out2; } if (strncmp(buf1, buf2, strlen(buf1))) { rc = EINVAL; splat_vprint(file, SPLAT_VNODE_TEST4_NAME, "Failed strncmp data written does not match " "data read\nWrote: %sRead: %s\n", buf1, buf2); goto out2; } rc = 0; splat_vprint(file, SPLAT_VNODE_TEST4_NAME, "Wrote to %s: %s", SPLAT_VNODE_TEST_FILE_RW1, buf1); splat_vprint(file, SPLAT_VNODE_TEST4_NAME, "Read from %s: %s", SPLAT_VNODE_TEST_FILE_RW2, buf2); splat_vprint(file, SPLAT_VNODE_TEST4_NAME, "Successfully renamed " "test file %s -> %s and verified data pattern\n", SPLAT_VNODE_TEST_FILE_RW1, SPLAT_VNODE_TEST_FILE_RW2); out2: VOP_CLOSE(vp, 0, 0, 0, 0, 0); out: vn_remove(SPLAT_VNODE_TEST_FILE_RW1, UIO_SYSSPACE, RMFILE); vn_remove(SPLAT_VNODE_TEST_FILE_RW2, UIO_SYSSPACE, RMFILE); return -rc; } /* splat_vnode_test4() */
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 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; char tempname[128]; /* * If the nvlist is empty (NULL), then remove the old cachefile. */ if (nvl == NULL) { (void) vn_remove(dp->scd_path, UIO_SYSSPACE, RMFILE); return; } /* * Pack the configuration into a buffer. */ VERIFY(nvlist_size(nvl, &buflen, NV_ENCODE_XDR) == 0); buf = kmem_alloc(buflen, KM_SLEEP); VERIFY(nvlist_pack(nvl, &buf, &buflen, NV_ENCODE_XDR, KM_SLEEP) == 0); #ifdef __APPLE_KERNEL__ /* * OS X - since vn_rename() and vn_remove() are both missing from * the KPI, we have to just write over the existing file! Since * the OS X cache file only contains pools that are built from * file VDEVs, this cache file should be small. */ (void) snprintf(tempname, sizeof (tempname), "%s", dp->scd_path); #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(tempname, sizeof (tempname), "%s.tmp", dp->scd_path); #endif if (vn_open(tempname, UIO_SYSSPACE, oflags, 0644, &vp, CRCREAT, 0) != 0) goto out; if (vn_rdwr(UIO_WRITE, vp, buf, buflen, 0, UIO_SYSSPACE, 0, RLIM64_INFINITY, kcred, NULL) == 0 && VOP_FSYNC(vp, FSYNC, kcred, NULL) == 0) { (void) vn_rename(tempname, dp->scd_path, UIO_SYSSPACE); } (void) VOP_CLOSE(vp, oflags, 1, 0, kcred, NULL); #ifndef __APPLE__ VN_RELE(vp); #endif out: (void) vn_remove(tempname, UIO_SYSSPACE, RMFILE); kmem_free(buf, buflen); }