]> git.proxmox.com Git - mirror_zfs.git/commitdiff
Fix kstat state update during pool transition
authorRichard Elling <Richard.Elling@RichardElling.com>
Thu, 23 May 2019 21:28:53 +0000 (14:28 -0700)
committerBrian Behlendorf <behlendorf1@llnl.gov>
Thu, 23 May 2019 21:28:53 +0000 (14:28 -0700)
When reading kstats, the health (aka state) of the pool is stored into
/proc/spl/kstat/zfs/POOLNAME/state via spa_state_to_name().
However, during import/export there is a case where the spa exists,
but the root vdev does not exist. This fix checks that case and sets
the state to "TRANSITIONING"

Unfortunately, it is not easy to reproduce a test for this. It was
detected randomly during ZTS runs while kstats were also being sampled
regularly. After this change, further testing did not trip on the case
and the TRANSITIONING state was collected at least once by the kstats.

For posterity, the backtrace prior to this fix is:
[Mon May 13 17:21:00 2019] RIP: 0010:spa_state_to_name+0x10/0xb0 [zfs]
...
Mon May 13 17:21:00 2019] Call Trace:
[Mon May 13 17:21:00 2019]  spa_state_data+0x1a/0x40 [zfs]
[Mon May 13 17:21:00 2019]  kstat_seq_show+0x117/0x440 [spl]
[Mon May 13 17:21:00 2019]  seq_read+0xe5/0x430
[Mon May 13 17:21:00 2019]  proc_reg_read+0x45/0x70
[Mon May 13 17:21:00 2019]  __vfs_read+0x1b/0x40
[Mon May 13 17:21:00 2019]  vfs_read+0x8e/0x130
[Mon May 13 17:21:00 2019]  SyS_read+0x55/0xc0
[Mon May 13 17:21:00 2019]  ? SyS_fcntl+0x5d/0xb0
[Mon May 13 17:21:00 2019]  do_syscall_64+0x73/0x130
[Mon May 13 17:21:00 2019]  entry_SYSCALL_64_after_hwframe+0x3d/0xa2

Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Reviewed-by: Tony Hutter <hutter2@llnl.gov>
Signed-off-by: Richard Elling <Richard.Elling@RichardElling.com>
Closes #8746

module/zfs/spa_misc.c

index e2d1ae3fcf130341082b8068e262d0a76b921353..dddbe9cfa0e4751790ce44314c9b036cecc67e7a 100644 (file)
@@ -2582,8 +2582,18 @@ spa_set_missing_tvds(spa_t *spa, uint64_t missing)
 const char *
 spa_state_to_name(spa_t *spa)
 {
-       vdev_state_t state = spa->spa_root_vdev->vdev_state;
-       vdev_aux_t aux = spa->spa_root_vdev->vdev_stat.vs_aux;
+       ASSERT3P(spa, !=, NULL);
+
+       /*
+        * it is possible for the spa to exist, without root vdev
+        * as the spa transitions during import/export
+        */
+       vdev_t *rvd = spa->spa_root_vdev;
+       if (rvd == NULL) {
+               return ("TRANSITIONING");
+       }
+       vdev_state_t state = rvd->vdev_state;
+       vdev_aux_t aux = rvd->vdev_stat.vs_aux;
 
        if (spa_suspended(spa) &&
            (spa_get_failmode(spa) != ZIO_FAILURE_MODE_CONTINUE))