diff --git a/CHANGELOG b/CHANGELOG
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,13 @@
+propellor (4.5.1) unstable; urgency=medium
+
+  * Reboot.toKernelNewerThan: If running kernel is new enough, avoid
+    looking at what kernels are installed.
+    Thanks, Sean Whitton.
+  * DiskImage: Avoid re-partitioning disk image unncessarily, for a large
+    speedup.
+
+ -- Joey Hess <id@joeyh.name>  Tue, 25 Jul 2017 15:51:33 -0400
+
 propellor (4.5.0) unstable; urgency=medium
 
   * Generalized the PartSpec DSL, so it can be used for both
diff --git a/debian/changelog b/debian/changelog
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,13 @@
+propellor (4.5.1) unstable; urgency=medium
+
+  * Reboot.toKernelNewerThan: If running kernel is new enough, avoid
+    looking at what kernels are installed.
+    Thanks, Sean Whitton.
+  * DiskImage: Avoid re-partitioning disk image unncessarily, for a large
+    speedup.
+
+ -- Joey Hess <id@joeyh.name>  Tue, 25 Jul 2017 15:51:33 -0400
+
 propellor (4.5.0) unstable; urgency=medium
 
   * Generalized the PartSpec DSL, so it can be used for both
diff --git a/joeyconfig.hs b/joeyconfig.hs
--- a/joeyconfig.hs
+++ b/joeyconfig.hs
@@ -4,6 +4,8 @@
 
 import Propellor
 import Propellor.Property.Scheduled
+import Propellor.Property.DiskImage
+import Propellor.Property.Chroot
 import qualified Propellor.Property.File as File
 import qualified Propellor.Property.Apt as Apt
 import qualified Propellor.Property.Network as Network
@@ -92,6 +94,16 @@
 	& Ssh.userKeys (User "joey") hostContext
 		[ (SshRsa, "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC1YoyHxZwG5Eg0yiMTJLSWJ/+dMM6zZkZiR4JJ0iUfP+tT2bm/lxYompbSqBeiCq+PYcSC67mALxp1vfmdOV//LWlbXfotpxtyxbdTcQbHhdz4num9rJQz1tjsOsxTEheX5jKirFNC5OiKhqwIuNydKWDS9qHGqsKcZQ8p+n1g9Lr3nJVGY7eRRXzw/HopTpwmGmAmb9IXY6DC2k91KReRZAlOrk0287LaK3eCe1z0bu7LYzqqS+w99iXZ/Qs0m9OqAPnHZjWQQ0fN4xn5JQpZSJ7sqO38TBAimM+IHPmy2FTNVVn9zGM+vN1O2xr3l796QmaUG1+XLL0shfR/OZbb joey@darkstar")
 		]
+	& imageBuilt "/srv/test.img" mychroot MSDOS
+		[ partition EXT2 `mountedAt` "/boot"
+		, partition EXT4 `mountedAt` "/"
+		, swapPartition (MegaBytes 256)
+		]
+  where
+	mychroot d = debootstrapped mempty d $ props
+		& osDebian Unstable X86_64
+		& Apt.installed ["linux-image-amd64"]
+		& Grub.installed PC
 
 gnu :: Host
 gnu = host "gnu.kitenet.net" $ props
diff --git a/propellor.cabal b/propellor.cabal
--- a/propellor.cabal
+++ b/propellor.cabal
@@ -1,5 +1,5 @@
 Name: propellor
-Version: 4.5.0
+Version: 4.5.1
 Cabal-Version: >= 1.20
 License: BSD2
 Maintainer: Joey Hess <id@joeyh.name>
diff --git a/src/Propellor/Property/DiskImage.hs b/src/Propellor/Property/DiskImage.hs
--- a/src/Propellor/Property/DiskImage.hs
+++ b/src/Propellor/Property/DiskImage.hs
@@ -174,16 +174,15 @@
 		let (mnts, mntopts, parttable) = fitChrootSize tabletype partspec $
 			map (calcsz mnts) mnts
 		ensureProperty w $
-			imageExists img (partTableSize parttable)
-				`before`
-			partitioned YesReallyDeleteDiskContents img parttable
+			imageExists' img parttable
 				`before`
 			kpartx img (mkimg' mnts mntopts parttable)
 	mkimg' mnts mntopts parttable devs =
 		partitionsPopulated chrootdir mnts mntopts devs
 			`before`
 		imageFinalized final mnts mntopts devs parttable
-	rmimg = File.notPresent img
+	rmimg = undoRevertableProperty (imageExists' img dummyparttable)
+	dummyparttable = PartTable tabletype []
 
 partitionsPopulated :: FilePath -> [Maybe MountPoint] -> [MountOpts] -> [LoopDev] -> Property DebianLike
 partitionsPopulated chrootdir mnts mntopts devs = property' desc $ \w ->
@@ -272,6 +271,29 @@
 	-- aligned to a sector size will confuse some programs.
 	-- Common sector sizes are 512 and 4096; use 4096 as it's larger.
 	sectorsize = 4096 :: Double
+
+-- | Ensure that disk image file exists and is partitioned.
+--
+-- Avoids repartitioning the disk image, when a file of the right size
+-- already exists, and it has the same PartTable.
+imageExists' :: FilePath -> PartTable -> RevertableProperty DebianLike UnixLike
+imageExists' img parttable = (setup <!> cleanup) `describe` desc
+  where
+	desc = "disk image exists " ++ img
+	parttablefile = img ++ ".parttable"
+	setup = property' desc $ \w -> do
+		oldparttable <- liftIO $ catchDefaultIO "" $ readFile parttablefile
+		res <- ensureProperty w $ imageExists img (partTableSize parttable)
+		if res == NoChange && oldparttable == show parttable
+			then return NoChange
+			else if res == FailedChange
+				then return FailedChange
+				else do
+					liftIO $ writeFile parttablefile (show parttable)
+					ensureProperty w $ partitioned YesReallyDeleteDiskContents img parttable
+	cleanup = File.notPresent img
+		`before`
+		File.notPresent parttablefile
 
 -- | A property that is run after the disk image is created, with
 -- its populated partition tree mounted in the provided
diff --git a/src/Propellor/Property/DiskImage/PartSpec.hs b/src/Propellor/Property/DiskImage/PartSpec.hs
--- a/src/Propellor/Property/DiskImage/PartSpec.hs
+++ b/src/Propellor/Property/DiskImage/PartSpec.hs
@@ -8,11 +8,15 @@
 module Propellor.Property.DiskImage.PartSpec (
 	module Propellor.Types.PartSpec,
 	module Propellor.Property.DiskImage.PartSpec,
+	module Propellor.Property.Parted.Types,
+	module Propellor.Property.Partition,
 ) where
 
 import Propellor.Base
 import Propellor.Property.Parted
 import Propellor.Types.PartSpec
+import Propellor.Property.Parted.Types
+import Propellor.Property.Partition (Fs(..))
 
 -- | Adds additional free space to the partition.
 addFreeSpace :: PartSpec t -> PartSize -> PartSpec t
diff --git a/src/Propellor/Property/Reboot.hs b/src/Propellor/Property/Reboot.hs
--- a/src/Propellor/Property/Reboot.hs
+++ b/src/Propellor/Property/Reboot.hs
@@ -78,15 +78,16 @@
 	property' ("reboot to kernel newer than " ++ ver) $ \w -> do
 		wantV <- tryReadVersion ver
 		runningV <- tryReadVersion =<< liftIO runningKernelVersion
-		installedV <- maximum <$>
-			(mapM tryReadVersion =<< liftIO installedKernelVersions)
 		if runningV >= wantV then noChange
-			else if installedV >= wantV
-				then ensureProperty w now
-				else errorMessage $
-					"kernel newer than "
-					++ ver
-					++ " not installed"
+			else maximum <$> installedVs >>= \installedV ->
+				if installedV >= wantV
+					then ensureProperty w now
+					else errorMessage $
+						"kernel newer than "
+						++ ver
+						++ " not installed"
+  where
+	installedVs = mapM tryReadVersion =<< liftIO installedKernelVersions
 
 runningInstalledKernel :: IO Bool
 runningInstalledKernel = do
