Print this page
3749 zfs event processing should work on R/O root filesystems
Submitted by:   Justin Gibbs <justing@spectralogic.com>
Reviewed by:    Matthew Ahrens <mahrens@delphix.com>
Reviewed by:    Eric Schrock <eric.schrock@delphix.com>

@@ -24,10 +24,11 @@
  * 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,25 +139,26 @@
                 kmem_free(buf, fsize);
 
         kobj_close_file(file);
 }
 
-static void
+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) {
-                (void) vn_remove(dp->scd_path, UIO_SYSSPACE, RMFILE);
-                return;
+                err = vn_remove(dp->scd_path, UIO_SYSSPACE, RMFILE);
+                return (err);
         }
 
         /*
          * Pack the configuration into a buffer.
          */

@@ -173,24 +175,27 @@
          * '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);
-                }
+        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,10 +203,12 @@
 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,10 +216,11 @@
         /*
          * 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,14 +257,36 @@
                         VERIFY(nvlist_add_nvlist(nvl, spa->spa_name,
                             spa->spa_config) == 0);
                         mutex_exit(&spa->spa_props_lock);
                 }
 
-                spa_config_write(dp, nvl);
+                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.
+                 */
+                if (target->spa_ccw_fail_time == 0) {
+                        zfs_ereport_post(FM_EREPORT_ZFS_CONFIG_CACHE_WRITE,
+                            target, NULL, NULL, 0, 0);
+                }
+                target->spa_ccw_fail_time = gethrtime();
+                spa_async_request(target, SPA_ASYNC_CONFIG_UPDATE);
+        } 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) {