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) {