Print this page
3749 zfs event processing should work on R/O root filesystems
Submitted by: Justin Gibbs <justing@spectralogic.com>
*** 24,33 ****
--- 24,34 ----
* Copyright 2011 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2012 by Delphix. All rights reserved.
*/
#include <sys/spa.h>
+ #include <sys/fm/fs/zfs.h>
#include <sys/spa_impl.h>
#include <sys/nvpair.h>
#include <sys/uio.h>
#include <sys/fs/zfs.h>
#include <sys/vdev_impl.h>
*** 138,162 ****
kmem_free(buf, fsize);
kobj_close_file(file);
}
! 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 *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.
*/
--- 139,164 ----
kmem_free(buf, fsize);
kobj_close_file(file);
}
! 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.
*/
*** 173,196 ****
* '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) {
! (void) vn_rename(temp, dp->scd_path, UIO_SYSSPACE);
! }
(void) VOP_CLOSE(vp, oflags, 1, 0, kcred, NULL);
VN_RELE(vp);
}
(void) vn_remove(temp, UIO_SYSSPACE, RMFILE);
kmem_free(buf, buflen);
kmem_free(temp, MAXPATHLEN);
}
/*
* Synchronize pool configuration to disk. This must be called with the
* namespace lock held.
--- 175,201 ----
* '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);
VN_RELE(vp);
}
(void) vn_remove(temp, UIO_SYSSPACE, RMFILE);
kmem_free(buf, buflen);
kmem_free(temp, MAXPATHLEN);
+ return (err);
}
/*
* Synchronize pool configuration to disk. This must be called with the
* namespace lock held.
*** 198,207 ****
--- 203,214 ----
void
spa_config_sync(spa_t *target, boolean_t removing, boolean_t postsysevent)
{
spa_config_dirent_t *dp, *tdp;
nvlist_t *nvl;
+ boolean_t ccw_failure;
+ int error;
ASSERT(MUTEX_HELD(&spa_namespace_lock));
if (rootdir == NULL || !(spa_mode_global & FWRITE))
return;
*** 209,218 ****
--- 216,226 ----
/*
* Iterate over all cachefiles for the pool, past or present. When the
* cachefile is changed, the new one is pushed onto this list, allowing
* us to update previous cachefiles that no longer contain this pool.
*/
+ ccw_failure = B_FALSE;
for (dp = list_head(&target->spa_config_list); dp != NULL;
dp = list_next(&target->spa_config_list, dp)) {
spa_t *spa = NULL;
if (dp->scd_path == NULL)
continue;
*** 249,262 ****
VERIFY(nvlist_add_nvlist(nvl, spa->spa_name,
spa->spa_config) == 0);
mutex_exit(&spa->spa_props_lock);
}
! spa_config_write(dp, nvl);
nvlist_free(nvl);
}
/*
* Remove any config entries older than the current one.
*/
dp = list_head(&target->spa_config_list);
while ((tdp = list_next(&target->spa_config_list, dp)) != NULL) {
--- 257,290 ----
VERIFY(nvlist_add_nvlist(nvl, spa->spa_name,
spa->spa_config) == 0);
mutex_exit(&spa->spa_props_lock);
}
! error = spa_config_write(dp, nvl);
! if (error != 0)
! ccw_failure = B_TRUE;
nvlist_free(nvl);
}
+ if (ccw_failure) {
+ /*
+ * Keep trying so that configuration data is
+ * written if/when any temporary filesystem
+ * resource issues are resolved.
+ */
+ target->spa_ccw_fail_time = ddi_get_lbolt64();
+ spa_async_request(target, SPA_ASYNC_CONFIG_UPDATE);
+ zfs_ereport_post(FM_EREPORT_ZFS_CONFIG_CACHE_WRITE,
+ target, NULL, NULL, 0, 0);
+ } else {
+ /*
+ * Do not rate limit future attempts to update
+ * the config cache.
+ */
+ target->spa_ccw_fail_time = 0;
+ }
+
/*
* Remove any config entries older than the current one.
*/
dp = list_head(&target->spa_config_list);
while ((tdp = list_next(&target->spa_config_list, dp)) != NULL) {