diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,10 @@
 # libarchive
 
+## 2.2.5.0
+
+  * Speed improvements in places
+  * Add `throwArchiveM` convenience function
+
 ## 2.2.4.0
 
   * Add convenience functions for `.xar` archives
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -7,7 +7,7 @@
 This contains Haskell bindings to
 [libarchive](http://libarchive.org/). It was created as an alternative to
 [tar](http://hackage.haskell.org/package/tar) and
-[tar-archive](http://hackage.haskell.org/package/tar-conduit), but it supports
+[tar-conduit](http://hackage.haskell.org/package/tar-conduit), but it supports
 more archive formats.
 
 It has a high-level Haskell API for creating and unpacking archives in addition
diff --git a/libarchive.cabal b/libarchive.cabal
--- a/libarchive.cabal
+++ b/libarchive.cabal
@@ -1,12 +1,12 @@
 cabal-version:   1.18
 name:            libarchive
-version:         2.2.4.0
+version:         2.2.5.0
 license:         BSD3
 license-file:    LICENSE
 copyright:       Copyright: (c) 2018-2020 Vanessa McHale
 maintainer:      vamchale@gmail.com
 author:          Vanessa McHale
-tested-with:     ghc ==8.4.4 ghc ==8.6.5 ghc ==8.8.3
+tested-with:     ghc ==8.4.4 ghc ==8.6.5 ghc ==8.8.3 ghc ==8.10.1
 bug-reports:     https://github.com/vmchale/libarchive/issues
 synopsis:        Haskell interface to libarchive
 description:
@@ -37,10 +37,6 @@
     description: Run low-memory version of test suite
     default:     False
 
-flag single-threaded
-    description: Run test suite without the threaded runtime
-    default:     False
-
 library
     exposed-modules:
         Codec.Archive
@@ -86,6 +82,9 @@
     if impl(ghc >=8.4)
         ghc-options: -Wmissing-export-lists
 
+    if impl(ghc >=8.10)
+        ghc-options: -Wunused-packages
+
 test-suite libarchive-test
     type:               exitcode-stdio-1.0
     main-is:            Spec.hs
@@ -99,7 +98,7 @@
     other-extensions:   OverloadedStrings
     ghc-options:
         -Wall -Wincomplete-uni-patterns -Wincomplete-record-updates
-        -Wredundant-constraints
+        -Wredundant-constraints -threaded -rtsopts -with-rtsopts=-N
 
     build-depends:
         base -any,
@@ -114,15 +113,15 @@
         composition-prelude >=2.0.5.0,
         pathological-bytestrings -any
 
-    if !flag(single-threaded)
-        ghc-options: -threaded -rtsopts -with-rtsopts=-N
-
     if flag(low-memory)
         cpp-options: -DLOW_MEMORY
 
     if impl(ghc >=8.4)
         ghc-options: -Wmissing-export-lists
 
+    if impl(ghc >=8.10)
+        ghc-options: -Wunused-packages
+
 benchmark libarchive-bench
     type:             exitcode-stdio-1.0
     main-is:          Bench.hs
@@ -143,3 +142,25 @@
 
     if impl(ghc >=8.4)
         ghc-options: -Wmissing-export-lists
+
+    if impl(ghc >=8.10)
+        ghc-options: -Wunused-packages
+
+benchmark mem
+    type:             exitcode-stdio-1.0
+    main-is:          Mem.hs
+    hs-source-dirs:   mem
+    default-language: Haskell2010
+    ghc-options:
+        -Wall -Wall -Wincomplete-uni-patterns -Wincomplete-record-updates
+        -Wredundant-constraints
+
+    build-depends:
+        base -any,
+        libarchive -any
+
+    if impl(ghc >=8.4)
+        ghc-options: -Wmissing-export-lists
+
+    if impl(ghc >=8.10)
+        ghc-options: -Wunused-packages
diff --git a/mem/Mem.hs b/mem/Mem.hs
new file mode 100644
--- /dev/null
+++ b/mem/Mem.hs
@@ -0,0 +1,14 @@
+module Main ( main ) where
+
+import           Codec.Archive
+import           Control.Exception (throw)
+
+forceList :: [a] -> IO ()
+forceList = (`seq` mempty) . last
+
+main :: IO ()
+main = readArc
+
+readArc :: IO ()
+readArc = either throw forceList =<< runArchiveM
+    (readArchiveFile "test/data/llvm-9.0.0.src.tar")
diff --git a/src/Codec/Archive.hs b/src/Codec/Archive.hs
--- a/src/Codec/Archive.hs
+++ b/src/Codec/Archive.hs
@@ -44,6 +44,7 @@
     -- * Archive monad
     , ArchiveM
     , runArchiveM
+    , throwArchiveM
     -- * Permissions helpers
     , standardPermissions
     , executablePermissions
diff --git a/src/Codec/Archive/Monad.hs b/src/Codec/Archive/Monad.hs
--- a/src/Codec/Archive/Monad.hs
+++ b/src/Codec/Archive/Monad.hs
@@ -1,6 +1,7 @@
 module Codec.Archive.Monad ( handle
                            , ignore
                            , runArchiveM
+                           , throwArchiveM
                            -- * Bracketed resources within 'ArchiveM'
                            , withCStringArchiveM
                            , useAsCStringLenArchiveM
@@ -10,12 +11,12 @@
                            ) where
 
 import           Codec.Archive.Types
-import           Control.Exception      (bracket)
+import           Control.Exception      (bracket, throw)
 import           Control.Monad          (void)
 import           Control.Monad.Except   (ExceptT, runExceptT, throwError)
 import           Control.Monad.IO.Class
-import           Data.ByteString        (useAsCStringLen)
 import qualified Data.ByteString        as BS
+import qualified Data.ByteString.Unsafe as BS
 import           Foreign.C.String
 import           Foreign.Marshal.Alloc  (allocaBytes)
 import           Foreign.Ptr            (Ptr)
@@ -26,6 +27,12 @@
 ignore :: IO ArchiveResult -> ArchiveM ()
 ignore = void . liftIO
 
+-- | Throws 'ArchiveResult' on error.
+--
+-- @since 2.2.5.0
+throwArchiveM :: ArchiveM a -> IO a
+throwArchiveM = fmap (either throw id) . runArchiveM
+
 runArchiveM :: ArchiveM a -> IO (Either ArchiveResult a)
 runArchiveM = runExceptT
 
@@ -57,7 +64,7 @@
 withCStringArchiveM = genBracket withCString
 
 useAsCStringLenArchiveM :: BS.ByteString -> (CStringLen -> ExceptT a IO b) -> ExceptT a IO b
-useAsCStringLenArchiveM = genBracket useAsCStringLen
+useAsCStringLenArchiveM = genBracket BS.unsafeUseAsCStringLen
 
 bracketM :: IO a -- ^ Allocate/aquire a resource
          -> (a -> IO b) -- ^ Free/release a resource (assumed not to fail)
diff --git a/src/Codec/Archive/Unpack.hs b/src/Codec/Archive/Unpack.hs
--- a/src/Codec/Archive/Unpack.hs
+++ b/src/Codec/Archive/Unpack.hs
@@ -11,7 +11,7 @@
 import           Codec.Archive.Monad
 import           Codec.Archive.Types
 import           Control.Monad          (void, (<=<))
-import           Control.Monad.IO.Class (MonadIO (..))
+import           Control.Monad.IO.Class (liftIO)
 import           Data.Bifunctor         (first)
 import qualified Data.ByteString        as BS
 import           Foreign.C.String
@@ -87,7 +87,7 @@
         Just x  -> Just <$> readEntry a x
 
 -- | Return a list of 'Entry's.
-hsEntries :: MonadIO m => Ptr Archive -> m [Entry]
+hsEntries :: Ptr Archive -> ArchiveM [Entry]
 hsEntries a = do
     next <- liftIO $ getHsEntry a
     case next of
diff --git a/src/Codec/Archive/Unpack/Lazy.hs b/src/Codec/Archive/Unpack/Lazy.hs
--- a/src/Codec/Archive/Unpack/Lazy.hs
+++ b/src/Codec/Archive/Unpack/Lazy.hs
@@ -9,8 +9,8 @@
 import           Codec.Archive.Unpack
 import           Control.Monad          ((<=<))
 import           Control.Monad.IO.Class
-import           Data.ByteString        (useAsCStringLen)
 import qualified Data.ByteString.Lazy   as BSL
+import qualified Data.ByteString.Unsafe as BS
 import           Data.Foldable          (traverse_)
 import           Data.Functor           (($>))
 import           Data.IORef             (modifyIORef, newIORef, readIORef, writeIORef)
@@ -68,7 +68,7 @@
                     [] -> pure 0
                     (x:_) -> do
                         modifyIORef bsRef tail
-                        useAsCStringLen x $ \(charPtr, sz) -> do
+                        BS.unsafeUseAsCStringLen x $ \(charPtr, sz) -> do
                             bufSz <- readIORef bufSzRef
                             bufPtr <- readIORef bufPtrRef
                             bufPtr' <- if sz > bufSz
