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>

Split Close
Expand all
Collapse all
          --- old/usr/src/uts/common/fs/zfs/spa_config.c
          +++ new/usr/src/uts/common/fs/zfs/spa_config.c
↓ open down ↓ 18 lines elided ↑ open up ↑
  19   19   * CDDL HEADER END
  20   20   */
  21   21  
  22   22  /*
  23   23   * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
  24   24   * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
  25   25   * Copyright (c) 2012 by Delphix. All rights reserved.
  26   26   */
  27   27  
  28   28  #include <sys/spa.h>
       29 +#include <sys/fm/fs/zfs.h>
  29   30  #include <sys/spa_impl.h>
  30   31  #include <sys/nvpair.h>
  31   32  #include <sys/uio.h>
  32   33  #include <sys/fs/zfs.h>
  33   34  #include <sys/vdev_impl.h>
  34   35  #include <sys/zfs_ioctl.h>
  35   36  #include <sys/utsname.h>
  36   37  #include <sys/systeminfo.h>
  37   38  #include <sys/sunddi.h>
  38   39  #include <sys/zfeature.h>
↓ open down ↓ 94 lines elided ↑ open up ↑
 133  134  
 134  135          nvlist_free(nvlist);
 135  136  
 136  137  out:
 137  138          if (buf != NULL)
 138  139                  kmem_free(buf, fsize);
 139  140  
 140  141          kobj_close_file(file);
 141  142  }
 142  143  
 143      -static void
      144 +static int
 144  145  spa_config_write(spa_config_dirent_t *dp, nvlist_t *nvl)
 145  146  {
 146  147          size_t buflen;
 147  148          char *buf;
 148  149          vnode_t *vp;
 149  150          int oflags = FWRITE | FTRUNC | FCREAT | FOFFMAX;
 150  151          char *temp;
      152 +        int err;
 151  153  
 152  154          /*
 153  155           * If the nvlist is empty (NULL), then remove the old cachefile.
 154  156           */
 155  157          if (nvl == NULL) {
 156      -                (void) vn_remove(dp->scd_path, UIO_SYSSPACE, RMFILE);
 157      -                return;
      158 +                err = vn_remove(dp->scd_path, UIO_SYSSPACE, RMFILE);
      159 +                return (err);
 158  160          }
 159  161  
 160  162          /*
 161  163           * Pack the configuration into a buffer.
 162  164           */
 163  165          VERIFY(nvlist_size(nvl, &buflen, NV_ENCODE_XDR) == 0);
 164  166  
 165  167          buf = kmem_alloc(buflen, KM_SLEEP);
 166  168          temp = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
 167  169  
 168  170          VERIFY(nvlist_pack(nvl, &buf, &buflen, NV_ENCODE_XDR,
 169  171              KM_SLEEP) == 0);
 170  172  
 171  173          /*
 172  174           * Write the configuration to disk.  We need to do the traditional
 173  175           * 'write to temporary file, sync, move over original' to make sure we
 174  176           * always have a consistent view of the data.
 175  177           */
 176  178          (void) snprintf(temp, MAXPATHLEN, "%s.tmp", dp->scd_path);
 177  179  
 178      -        if (vn_open(temp, UIO_SYSSPACE, oflags, 0644, &vp, CRCREAT, 0) == 0) {
 179      -                if (vn_rdwr(UIO_WRITE, vp, buf, buflen, 0, UIO_SYSSPACE,
 180      -                    0, RLIM64_INFINITY, kcred, NULL) == 0 &&
 181      -                    VOP_FSYNC(vp, FSYNC, kcred, NULL) == 0) {
 182      -                        (void) vn_rename(temp, dp->scd_path, UIO_SYSSPACE);
 183      -                }
      180 +        err = vn_open(temp, UIO_SYSSPACE, oflags, 0644, &vp, CRCREAT, 0);
      181 +        if (err == 0) {
      182 +                err = vn_rdwr(UIO_WRITE, vp, buf, buflen, 0, UIO_SYSSPACE,
      183 +                    0, RLIM64_INFINITY, kcred, NULL);
      184 +                if (err == 0)
      185 +                        err = VOP_FSYNC(vp, FSYNC, kcred, NULL);
      186 +                if (err == 0)
      187 +                        err = vn_rename(temp, dp->scd_path, UIO_SYSSPACE);
 184  188                  (void) VOP_CLOSE(vp, oflags, 1, 0, kcred, NULL);
 185  189                  VN_RELE(vp);
 186  190          }
 187  191  
 188  192          (void) vn_remove(temp, UIO_SYSSPACE, RMFILE);
 189  193  
 190  194          kmem_free(buf, buflen);
 191  195          kmem_free(temp, MAXPATHLEN);
      196 +        return (err);
 192  197  }
 193  198  
 194  199  /*
 195  200   * Synchronize pool configuration to disk.  This must be called with the
 196  201   * namespace lock held.
 197  202   */
 198  203  void
 199  204  spa_config_sync(spa_t *target, boolean_t removing, boolean_t postsysevent)
 200  205  {
 201  206          spa_config_dirent_t *dp, *tdp;
 202  207          nvlist_t *nvl;
      208 +        boolean_t ccw_failure;
      209 +        int error;
 203  210  
 204  211          ASSERT(MUTEX_HELD(&spa_namespace_lock));
 205  212  
 206  213          if (rootdir == NULL || !(spa_mode_global & FWRITE))
 207  214                  return;
 208  215  
 209  216          /*
 210  217           * Iterate over all cachefiles for the pool, past or present.  When the
 211  218           * cachefile is changed, the new one is pushed onto this list, allowing
 212  219           * us to update previous cachefiles that no longer contain this pool.
 213  220           */
      221 +        ccw_failure = B_FALSE;
 214  222          for (dp = list_head(&target->spa_config_list); dp != NULL;
 215  223              dp = list_next(&target->spa_config_list, dp)) {
 216  224                  spa_t *spa = NULL;
 217  225                  if (dp->scd_path == NULL)
 218  226                          continue;
 219  227  
 220  228                  /*
 221  229                   * Iterate over all pools, adding any matching pools to 'nvl'.
 222  230                   */
 223  231                  nvl = NULL;
↓ open down ↓ 20 lines elided ↑ open up ↑
 244  252  
 245  253                          if (nvl == NULL)
 246  254                                  VERIFY(nvlist_alloc(&nvl, NV_UNIQUE_NAME,
 247  255                                      KM_SLEEP) == 0);
 248  256  
 249  257                          VERIFY(nvlist_add_nvlist(nvl, spa->spa_name,
 250  258                              spa->spa_config) == 0);
 251  259                          mutex_exit(&spa->spa_props_lock);
 252  260                  }
 253  261  
 254      -                spa_config_write(dp, nvl);
      262 +                error = spa_config_write(dp, nvl);
      263 +                if (error != 0)
      264 +                        ccw_failure = B_TRUE;
 255  265                  nvlist_free(nvl);
 256  266          }
 257  267  
      268 +        if (ccw_failure) {
      269 +                /*
      270 +                 * Keep trying so that configuration data is
      271 +                 * written if/when any temporary filesystem
      272 +                 * resource issues are resolved.
      273 +                 */
      274 +                if (target->spa_ccw_fail_time == 0) {
      275 +                        zfs_ereport_post(FM_EREPORT_ZFS_CONFIG_CACHE_WRITE,
      276 +                            target, NULL, NULL, 0, 0);
      277 +                }
      278 +                target->spa_ccw_fail_time = gethrtime();
      279 +                spa_async_request(target, SPA_ASYNC_CONFIG_UPDATE);
      280 +        } else {
      281 +                /*
      282 +                 * Do not rate limit future attempts to update
      283 +                 * the config cache.
      284 +                 */
      285 +                target->spa_ccw_fail_time = 0;
      286 +        }
      287 +
 258  288          /*
 259  289           * Remove any config entries older than the current one.
 260  290           */
 261  291          dp = list_head(&target->spa_config_list);
 262  292          while ((tdp = list_next(&target->spa_config_list, dp)) != NULL) {
 263  293                  list_remove(&target->spa_config_list, tdp);
 264  294                  if (tdp->scd_path != NULL)
 265  295                          spa_strfree(tdp->scd_path);
 266  296                  kmem_free(tdp, sizeof (spa_config_dirent_t));
 267  297          }
↓ open down ↓ 241 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX