diff --git a/ChangeLog b/ChangeLog
deleted file mode 100644
--- a/ChangeLog
+++ /dev/null
@@ -1,26 +0,0 @@
-v0.1.2.3
-
-	* System.Linux.Btrfs.UUID.fromString did not handle all malformed
-	UUIDs correctly.
-
-v0.1.2.2
-
-	* Fix compilation error when libcap is not installed.
-
-v0.1.2.1
-
-	* Support cloneRangeIfSame on read-only subvolumes (requires
-	CAP_SYS_ADMIN).
-
-v0.1.2.0
-
-	* Expose System.Linux.Btrfs.Time.
-	* Add example program that prints the file creation timestamp.
-
-v0.1.1.1
-
-	* Support getting/setting the id of the default subvolume.
-
-v0.1.1.0
-
-	* Support defraging file ranges.
diff --git a/ChangeLog.md b/ChangeLog.md
new file mode 100644
--- /dev/null
+++ b/ChangeLog.md
@@ -0,0 +1,40 @@
+#### 0.2.0.0 *2018-10-25*
+
+	* Implement getFSInfo.
+	* Remove an ugly hack that was used to block signals while defrag was running.
+	* Support Zstd compression.
+	* Make CompressionType abstract.
+	* Fix handling of filenames that are not valid according to the current locale.
+	* Deprecate System.Linux.Btrfs.ByteString.
+	* Support getting/setting file system labels.
+
+#### 0.1.2.3 *2017-01-30*
+
+	* System.Linux.Btrfs.UUID.fromString did not handle all malformed
+	UUIDs correctly.
+
+#### 0.1.2.2 *2016-11-15*
+
+	* Fix compilation error when libcap is not installed.
+
+#### 0.1.2.1 *2016-11-13*
+
+	* Support cloneRangeIfSame on read-only subvolumes (requires
+	CAP_SYS_ADMIN).
+
+#### 0.1.2.0 *2016-02-23*
+
+	* Expose System.Linux.Btrfs.Time.
+	* Add example program that prints the file creation timestamp.
+
+#### 0.1.1.1 *2014-10-05*
+
+	* Support getting/setting the id of the default subvolume.
+
+#### 0.1.1.0 *2014-10-05*
+
+	* Support defraging file ranges.
+
+#### 0.1.0.0 *2014-09-01*
+
+	* Initial public release.
diff --git a/System/Linux/Btrfs.hsc b/System/Linux/Btrfs.hsc
--- a/System/Linux/Btrfs.hsc
+++ b/System/Linux/Btrfs.hsc
@@ -16,13 +16,18 @@
 #if BTRFS_RAW_PATHS
 ##define FILEPATH RawFilePath
 module System.Linux.Btrfs.ByteString
+{-# DEPRECATED "This module is deprecated and will be removed in a\
+ future version of this library. Please leave a comment on\
+ https://github.com/redneb/hs-btrfs/issues/5 if you think that is\
+ should not be removed." #-}
 #else
 ##define FILEPATH FilePath
 module System.Linux.Btrfs
 #endif
     (
     -- * Basic types
-      FileSize, ObjectType, ObjectId, InodeNum, SubvolId, CompressionType(..)
+      FileSize, ObjectType, ObjectId, InodeNum, SubvolId
+    , CompressionType, compressNone, compressZlib, compressLZO, compressZstd
     -- * File cloning/deduplication
     , cloneFd, clone, cloneNew
     , cloneRangeFd, cloneRange
@@ -48,10 +53,26 @@
     , getSubvolByReceivedUuidFd, getSubvolByReceivedUuid
     , getDefaultSubvolFd, getDefaultSubvol
     , setDefaultSubvolFd, setDefaultSubvol
-    -- * Defragging
+    -- * Defrag
+    -- | There is a limitation in the kernel whereby a defrag operation
+    -- will be silently aborted when the calling process receives any
+    -- signal. This does not play well with GHC's rts which in some
+    -- cases uses signals as a way to preempt haskell threads. So in order
+    -- to use 'defrag' or 'defragRange', you must compile your program with
+    -- GHC >=8.2 and the use the threaded runtime which does not use
+    -- signals anymore. Alternatively, for older versions of GHC, you can
+    -- use something like the @withRTSSignalsBlocked@ function from
+    -- <http://www.serpentine.com/blog/2010/09/04/dealing-with-fragile-c-libraries-e-g-mysql-from-haskell/ here>.
     , defragFd, defrag
     , DefragRangeArgs(..), defaultDefragRangeArgs
     , defragRangeFd, defragRange
+    -- * File system info
+    , FSInfo
+    , fsiDeviceCount, fsiUuid, fsiNodeSize, fsiSectorSize, fsiCloneAlignment
+    , getFSInfoFd, getFSInfo
+    -- * File system label
+    , getFSLabelFd, getFSLabel
+    , setFSLabelFd, setFSLabel
     -- * Sync
     , syncFd, sync
     , startSyncFd, startSync
@@ -77,7 +98,6 @@
 import System.Posix.Types
 import System.Posix.IO hiding (openFd)
 import System.Posix.Files
-import System.Posix.Signals
 import System.IO.Error
 import Control.Exception
 import Control.Monad
@@ -117,9 +137,23 @@
 
 type SubvolId = ObjectId
 
-data CompressionType = Zlib | LZO
-    deriving (Show, Read, Eq, Enum, Bounded)
+newtype CompressionType = CompressionType Word32
+    deriving Eq
 
+instance Show CompressionType where
+    show t
+        | t == compressNone = "compressNone"
+        | t == compressZlib = "compressZlib"
+        | t == compressLZO  = "compressLZO"
+        | t == compressZstd = "compressZstd"
+        | otherwise = error "unknown compression type"
+
+compressNone, compressZlib, compressLZO, compressZstd :: CompressionType
+compressNone = CompressionType (#const BTRFS_COMPRESS_NONE)
+compressZlib = CompressionType (#const BTRFS_COMPRESS_ZLIB)
+compressLZO  = CompressionType (#const BTRFS_COMPRESS_LZO)
+compressZstd = CompressionType (#const BTRFS_COMPRESS_ZSTD)
+
 --------------------------------------------------------------------------------
 
 cloneFd :: Fd -> Fd -> IO ()
@@ -164,7 +198,8 @@
             ioctl_fast dstFd (#const BTRFS_IOC_CLONE_RANGE) cra
 
 -- | Clones a range of bytes from a file to another file. All ranges must
--- be block-aligned.
+-- be block-aligned (the block size can be obtained using 'getFSInfo' and
+-- 'fsiCloneAlignment').
 --
 -- Note: calls the @BTRFS_IOC_CLONE_RANGE@/@FICLONERANGE@ @ioctl@.
 cloneRange
@@ -697,7 +732,7 @@
     l <- treeSearchListFd fd sk $ \_ ptr -> do
         LE16 nameLen <- (#peek struct btrfs_dir_item, name_len) ptr
         let cName = ptr `plusPtr` (#size struct btrfs_dir_item)
-        name <- peekCStringLen (cName, fromIntegral nameLen)
+        name <- peekFilePathLen (cName, fromIntegral nameLen)
         if name /= "default" then
             return Nothing
         else do
@@ -737,8 +772,7 @@
 defragFd :: Fd -> IO ()
 defragFd fd =
     throwErrnoIfMinus1_ "defragFd" $
-        withBlockSIGVTALRM $ -- this is probably a bad idea
-            ioctl fd (#const BTRFS_IOC_DEFRAG) nullPtr
+        ioctl fd (#const BTRFS_IOC_DEFRAG) nullPtr
 
 -- | Defrag a single file.
 --
@@ -755,7 +789,7 @@
     , draExtentThreshold :: Word32
         -- ^ Any extent of size bigger or equal to this number will be
         -- considered already defragged. Use 0 for the kernel default.
-    , draCompress :: Maybe CompressionType
+    , draCompress :: CompressionType
         -- ^ Compress the file while defragmenting.
     , draFlush :: Bool
         -- ^ Flush data to disk immediately after defragmenting.
@@ -769,7 +803,7 @@
     { draStart = 0
     , draLength = maxBound
     , draExtentThreshold = 0
-    , draCompress = Nothing
+    , draCompress = compressNone
     , draFlush = False
     }
 
@@ -782,17 +816,14 @@
         (#poke struct btrfs_ioctl_defrag_range_args, extent_thresh) args draExtentThreshold
         (#poke struct btrfs_ioctl_defrag_range_args, compress_type) args comp_type
         throwErrnoIfMinus1_ "defragRangeFd" $
-            withBlockSIGVTALRM $ -- this is probably a bad idea
-                ioctl fd (#const BTRFS_IOC_DEFRAG_RANGE) args
+            ioctl fd (#const BTRFS_IOC_DEFRAG_RANGE) args
   where
+    flags :: Word64
     flags = comp_flags .|. if draFlush then (#const BTRFS_DEFRAG_RANGE_START_IO) else 0
-    comp_flags :: Word64
-    comp_type :: Word32
-    (comp_flags, comp_type) =
-        case draCompress of
-            Nothing -> (0, 0)
-            Just Zlib -> ((#const BTRFS_DEFRAG_RANGE_COMPRESS), (#const BTRFS_COMPRESS_ZLIB))
-            Just LZO  -> ((#const BTRFS_DEFRAG_RANGE_COMPRESS), (#const BTRFS_COMPRESS_LZO))
+    comp_flags
+        | draCompress == compressNone = 0
+        | otherwise = (#const BTRFS_DEFRAG_RANGE_COMPRESS)
+    CompressionType comp_type = draCompress
 
 -- | Defrag a range within a single file.
 --
@@ -804,6 +835,93 @@
 
 --------------------------------------------------------------------------------
 
+-- | Information about a btrfs file system.
+data FSInfo = FSInfo
+    { fsiDeviceCount :: Word64
+        -- ^ The number of devices in the file system.
+    , fsiUuid :: UUID
+        -- ^ The UUID of the file system.
+    , fsiNodeSize :: FileSize
+        -- ^ The tree block size in which metadata is stored.
+    , fsiSectorSize :: FileSize
+        -- ^ The minimum data block allocation unit.
+    , fsiCloneAlignment :: FileSize
+        -- ^ The size that is used for the alignment constraints of clone
+        -- range operations.
+    }
+  deriving (Show, Eq)
+
+getFSInfoFd :: Fd -> IO FSInfo
+getFSInfoFd fd =
+    allocaBytes (#size struct btrfs_ioctl_fs_info_args) $ \fsia -> do
+        throwErrnoIfMinus1_ "getFSInfoFd" $
+            ioctl_fast fd (#const BTRFS_IOC_FS_INFO) fsia
+        nd <- (#peek struct btrfs_ioctl_fs_info_args, num_devices) fsia :: IO Word64
+        uuid <- (#peek struct btrfs_ioctl_fs_info_args, fsid) fsia :: IO UUID
+        ns <- (#peek struct btrfs_ioctl_fs_info_args, nodesize) fsia :: IO Word32
+        ss <- (#peek struct btrfs_ioctl_fs_info_args, sectorsize) fsia :: IO Word32
+        ca <- (#peek struct btrfs_ioctl_fs_info_args, clone_alignment) fsia :: IO Word32
+        return FSInfo
+            { fsiDeviceCount = nd
+            , fsiUuid = uuid
+            , fsiNodeSize = fromIntegral ns
+            , fsiSectorSize = fromIntegral ss
+            , fsiCloneAlignment = fromIntegral ca
+            }
+
+-- | Retrieve information about a btrfs file system.
+--
+-- Note: calls the @BTRFS_IOC_FS_INFO@ @ioctl@.
+getFSInfo
+    :: FILEPATH -- ^ The mount point of the volume (or any file in that volume).
+    -> IO FSInfo
+getFSInfo path =
+    withFd path ReadOnly getFSInfoFd
+
+--------------------------------------------------------------------------------
+
+getFSLabelFd :: Fd -> IO FILEPATH
+getFSLabelFd fd =
+    allocaBytesZero maxLabelSize $ \ptr -> do
+        throwErrnoIfMinus1_ "getFSLabelFd" $
+            ioctl_fast fd (#const BTRFS_IOC_GET_FSLABEL) ptr
+        peekFilePath ptr
+
+-- | Retrieve the label of a btrfs file system.
+--
+-- Note: calls the @BTRFS_IOC_GET_FSLABEL@ @ioctl@.
+getFSLabel
+    :: FILEPATH -- ^ The mount point of the volume (or any file in that volume).
+    -> IO FILEPATH
+getFSLabel path =
+    withFd path ReadOnly getFSLabelFd
+
+setFSLabelFd :: Fd -> FILEPATH -> IO ()
+setFSLabelFd fd label =
+    withFilePathLen label $ \(ptr, len) ->
+        allocaBytesZero maxLabelSize $ \buf -> do
+            copyArray buf ptr (min len (maxLabelSize - 1))
+            throwErrnoIfMinus1_ "setFSLabelFd" $
+                ioctl fd (#const BTRFS_IOC_SET_FSLABEL) buf
+
+-- | Set the label of a btrfs file system. Note that a label can be up to
+-- 255 /bytes/ long. If the provided label is longer, it will be silently
+-- truncated.
+--
+-- Note: calls the @BTRFS_IOC_SET_FSLABEL@ @ioctl@.
+setFSLabel
+    :: FILEPATH -- ^ The mount point of the volume (or any file in that volume).
+    -> FILEPATH -- ^ The new label.
+    -> IO ()
+setFSLabel path label =
+    withFd path ReadOnly $ \fd ->
+        setFSLabelFd fd label
+
+maxLabelSize :: Int
+maxLabelSize = (#const BTRFS_LABEL_SIZE)
+
+--------------------------------------------------------------------------------
+
 syncFd :: Fd -> IO ()
 syncFd fd =
     throwErrnoIfMinus1_ "syncFd" $
@@ -888,7 +1006,7 @@
         count      <- (#peek struct btrfs_data_container, elem_cnt   ) fspath :: IO Word32
         let val = (#ptr struct btrfs_data_container, val) fspath :: Ptr Word64
         vals <- peekArray (fromIntegral count) val
-        paths <- mapM (peekCString . plusPtr val . fromIntegral) vals
+        paths <- mapM (peekFilePath . plusPtr val . fromIntegral) vals
         return (paths, fromIntegral elemMissed)
   where
     fspathSize = 2 * 1024 + (#size struct btrfs_data_container)
@@ -917,7 +1035,7 @@
             ioctl_fast fd (#const BTRFS_IOC_INO_LOOKUP) ila
         treeId' <- (#peek struct btrfs_ioctl_ino_lookup_args, treeid) ila :: IO Word64
         let cName = (#ptr struct btrfs_ioctl_ino_lookup_args, name) ila
-        name <- peekCString cName
+        name <- peekFilePath cName
         return (treeId', dropTrailingSlash name)
 
 -- | Find the path of a file given its inode number and the id of the
@@ -1122,7 +1240,7 @@
     LE64 dirId   <- (#peek struct btrfs_root_ref, dirid   ) rrPtr
     LE16 nameLen <- (#peek struct btrfs_root_ref, name_len) rrPtr
     let cName = rrPtr `plusPtr` (#size struct btrfs_root_ref)
-    name <- peekCStringLen (cName, fromIntegral nameLen)
+    name <- peekFilePathLen (cName, fromIntegral nameLen)
     return (dirId, name)
 
 --------------------------------------------------------------------------------
@@ -1134,19 +1252,13 @@
 
 withSplitPathOpenParent :: String -> Int -> FILEPATH -> (CStringLen -> Fd -> IO r) -> IO r
 withSplitPathOpenParent loc maxLen path action =
-    unsafeWithCStringLen name $ \cName @ (_, l) -> do
+    unsafeWithFilePathLen name $ \cName @ (_, l) -> do
         unless (l <= maxLen) $
             ioError $ flip ioeSetErrorString "the subvolume name is too long"
                     $ mkIOError illegalOperationErrorType loc Nothing (Just (asString name))
         withFd dir ReadOnly $ action cName
   where
     (dir, name) = splitFileName (dropTrailingSlash path)
-
-withBlockSIGVTALRM :: IO a -> IO a
-withBlockSIGVTALRM =
-    bracket_ (blockSignals s) (unblockSignals s)
-  where
-    s = addSignal sigVTALRM emptySignalSet
 
 nothingIf :: Bool -> a -> Maybe a
 nothingIf f v = if f then Nothing else Just v
diff --git a/System/Linux/Btrfs/ByteString.hsc b/System/Linux/Btrfs/ByteString.hsc
--- a/System/Linux/Btrfs/ByteString.hsc
+++ b/System/Linux/Btrfs/ByteString.hsc
@@ -16,13 +16,18 @@
 #if BTRFS_RAW_PATHS
 ##define FILEPATH RawFilePath
 module System.Linux.Btrfs.ByteString
+{-# DEPRECATED "This module is deprecated and will be removed in a\
+ future version of this library. Please leave a comment on\
+ https://github.com/redneb/hs-btrfs/issues/5 if you think that is\
+ should not be removed." #-}
 #else
 ##define FILEPATH FilePath
 module System.Linux.Btrfs
 #endif
     (
     -- * Basic types
-      FileSize, ObjectType, ObjectId, InodeNum, SubvolId, CompressionType(..)
+      FileSize, ObjectType, ObjectId, InodeNum, SubvolId
+    , CompressionType, compressNone, compressZlib, compressLZO, compressZstd
     -- * File cloning/deduplication
     , cloneFd, clone, cloneNew
     , cloneRangeFd, cloneRange
@@ -48,10 +53,26 @@
     , getSubvolByReceivedUuidFd, getSubvolByReceivedUuid
     , getDefaultSubvolFd, getDefaultSubvol
     , setDefaultSubvolFd, setDefaultSubvol
-    -- * Defragging
+    -- * Defrag
+    -- | There is a limitation in the kernel whereby a defrag operation
+    -- will be silently aborted when the calling process receives any
+    -- signal. This does not play well with GHC's rts which in some
+    -- cases uses signals as a way to preempt haskell threads. So in order
+    -- to use 'defrag' or 'defragRange', you must compile your program with
+    -- GHC >=8.2 and the use the threaded runtime which does not use
+    -- signals anymore. Alternatively, for older versions of GHC, you can
+    -- use something like the @withRTSSignalsBlocked@ function from
+    -- <http://www.serpentine.com/blog/2010/09/04/dealing-with-fragile-c-libraries-e-g-mysql-from-haskell/ here>.
     , defragFd, defrag
     , DefragRangeArgs(..), defaultDefragRangeArgs
     , defragRangeFd, defragRange
+    -- * File system info
+    , FSInfo
+    , fsiDeviceCount, fsiUuid, fsiNodeSize, fsiSectorSize, fsiCloneAlignment
+    , getFSInfoFd, getFSInfo
+    -- * File system label
+    , getFSLabelFd, getFSLabel
+    , setFSLabelFd, setFSLabel
     -- * Sync
     , syncFd, sync
     , startSyncFd, startSync
@@ -77,7 +98,6 @@
 import System.Posix.Types
 import System.Posix.IO hiding (openFd)
 import System.Posix.Files
-import System.Posix.Signals
 import System.IO.Error
 import Control.Exception
 import Control.Monad
@@ -117,9 +137,23 @@
 
 type SubvolId = ObjectId
 
-data CompressionType = Zlib | LZO
-    deriving (Show, Read, Eq, Enum, Bounded)
+newtype CompressionType = CompressionType Word32
+    deriving Eq
 
+instance Show CompressionType where
+    show t
+        | t == compressNone = "compressNone"
+        | t == compressZlib = "compressZlib"
+        | t == compressLZO  = "compressLZO"
+        | t == compressZstd = "compressZstd"
+        | otherwise = error "unknown compression type"
+
+compressNone, compressZlib, compressLZO, compressZstd :: CompressionType
+compressNone = CompressionType (#const BTRFS_COMPRESS_NONE)
+compressZlib = CompressionType (#const BTRFS_COMPRESS_ZLIB)
+compressLZO  = CompressionType (#const BTRFS_COMPRESS_LZO)
+compressZstd = CompressionType (#const BTRFS_COMPRESS_ZSTD)
+
 --------------------------------------------------------------------------------
 
 cloneFd :: Fd -> Fd -> IO ()
@@ -164,7 +198,8 @@
             ioctl_fast dstFd (#const BTRFS_IOC_CLONE_RANGE) cra
 
 -- | Clones a range of bytes from a file to another file. All ranges must
--- be block-aligned.
+-- be block-aligned (the block size can be obtained using 'getFSInfo' and
+-- 'fsiCloneAlignment').
 --
 -- Note: calls the @BTRFS_IOC_CLONE_RANGE@/@FICLONERANGE@ @ioctl@.
 cloneRange
@@ -697,7 +732,7 @@
     l <- treeSearchListFd fd sk $ \_ ptr -> do
         LE16 nameLen <- (#peek struct btrfs_dir_item, name_len) ptr
         let cName = ptr `plusPtr` (#size struct btrfs_dir_item)
-        name <- peekCStringLen (cName, fromIntegral nameLen)
+        name <- peekFilePathLen (cName, fromIntegral nameLen)
         if name /= "default" then
             return Nothing
         else do
@@ -737,8 +772,7 @@
 defragFd :: Fd -> IO ()
 defragFd fd =
     throwErrnoIfMinus1_ "defragFd" $
-        withBlockSIGVTALRM $ -- this is probably a bad idea
-            ioctl fd (#const BTRFS_IOC_DEFRAG) nullPtr
+        ioctl fd (#const BTRFS_IOC_DEFRAG) nullPtr
 
 -- | Defrag a single file.
 --
@@ -755,7 +789,7 @@
     , draExtentThreshold :: Word32
         -- ^ Any extent of size bigger or equal to this number will be
         -- considered already defragged. Use 0 for the kernel default.
-    , draCompress :: Maybe CompressionType
+    , draCompress :: CompressionType
         -- ^ Compress the file while defragmenting.
     , draFlush :: Bool
         -- ^ Flush data to disk immediately after defragmenting.
@@ -769,7 +803,7 @@
     { draStart = 0
     , draLength = maxBound
     , draExtentThreshold = 0
-    , draCompress = Nothing
+    , draCompress = compressNone
     , draFlush = False
     }
 
@@ -782,17 +816,14 @@
         (#poke struct btrfs_ioctl_defrag_range_args, extent_thresh) args draExtentThreshold
         (#poke struct btrfs_ioctl_defrag_range_args, compress_type) args comp_type
         throwErrnoIfMinus1_ "defragRangeFd" $
-            withBlockSIGVTALRM $ -- this is probably a bad idea
-                ioctl fd (#const BTRFS_IOC_DEFRAG_RANGE) args
+            ioctl fd (#const BTRFS_IOC_DEFRAG_RANGE) args
   where
+    flags :: Word64
     flags = comp_flags .|. if draFlush then (#const BTRFS_DEFRAG_RANGE_START_IO) else 0
-    comp_flags :: Word64
-    comp_type :: Word32
-    (comp_flags, comp_type) =
-        case draCompress of
-            Nothing -> (0, 0)
-            Just Zlib -> ((#const BTRFS_DEFRAG_RANGE_COMPRESS), (#const BTRFS_COMPRESS_ZLIB))
-            Just LZO  -> ((#const BTRFS_DEFRAG_RANGE_COMPRESS), (#const BTRFS_COMPRESS_LZO))
+    comp_flags
+        | draCompress == compressNone = 0
+        | otherwise = (#const BTRFS_DEFRAG_RANGE_COMPRESS)
+    CompressionType comp_type = draCompress
 
 -- | Defrag a range within a single file.
 --
@@ -804,6 +835,93 @@
 
 --------------------------------------------------------------------------------
 
+-- | Information about a btrfs file system.
+data FSInfo = FSInfo
+    { fsiDeviceCount :: Word64
+        -- ^ The number of devices in the file system.
+    , fsiUuid :: UUID
+        -- ^ The UUID of the file system.
+    , fsiNodeSize :: FileSize
+        -- ^ The tree block size in which metadata is stored.
+    , fsiSectorSize :: FileSize
+        -- ^ The minimum data block allocation unit.
+    , fsiCloneAlignment :: FileSize
+        -- ^ The size that is used for the alignment constraints of clone
+        -- range operations.
+    }
+  deriving (Show, Eq)
+
+getFSInfoFd :: Fd -> IO FSInfo
+getFSInfoFd fd =
+    allocaBytes (#size struct btrfs_ioctl_fs_info_args) $ \fsia -> do
+        throwErrnoIfMinus1_ "getFSInfoFd" $
+            ioctl_fast fd (#const BTRFS_IOC_FS_INFO) fsia
+        nd <- (#peek struct btrfs_ioctl_fs_info_args, num_devices) fsia :: IO Word64
+        uuid <- (#peek struct btrfs_ioctl_fs_info_args, fsid) fsia :: IO UUID
+        ns <- (#peek struct btrfs_ioctl_fs_info_args, nodesize) fsia :: IO Word32
+        ss <- (#peek struct btrfs_ioctl_fs_info_args, sectorsize) fsia :: IO Word32
+        ca <- (#peek struct btrfs_ioctl_fs_info_args, clone_alignment) fsia :: IO Word32
+        return FSInfo
+            { fsiDeviceCount = nd
+            , fsiUuid = uuid
+            , fsiNodeSize = fromIntegral ns
+            , fsiSectorSize = fromIntegral ss
+            , fsiCloneAlignment = fromIntegral ca
+            }
+
+-- | Retrieve information about a btrfs file system.
+--
+-- Note: calls the @BTRFS_IOC_FS_INFO@ @ioctl@.
+getFSInfo
+    :: FILEPATH -- ^ The mount point of the volume (or any file in that volume).
+    -> IO FSInfo
+getFSInfo path =
+    withFd path ReadOnly getFSInfoFd
+
+--------------------------------------------------------------------------------
+
+getFSLabelFd :: Fd -> IO FILEPATH
+getFSLabelFd fd =
+    allocaBytesZero maxLabelSize $ \ptr -> do
+        throwErrnoIfMinus1_ "getFSLabelFd" $
+            ioctl_fast fd (#const BTRFS_IOC_GET_FSLABEL) ptr
+        peekFilePath ptr
+
+-- | Retrieve the label of a btrfs file system.
+--
+-- Note: calls the @BTRFS_IOC_GET_FSLABEL@ @ioctl@.
+getFSLabel
+    :: FILEPATH -- ^ The mount point of the volume (or any file in that volume).
+    -> IO FILEPATH
+getFSLabel path =
+    withFd path ReadOnly getFSLabelFd
+
+setFSLabelFd :: Fd -> FILEPATH -> IO ()
+setFSLabelFd fd label =
+    withFilePathLen label $ \(ptr, len) ->
+        allocaBytesZero maxLabelSize $ \buf -> do
+            copyArray buf ptr (min len (maxLabelSize - 1))
+            throwErrnoIfMinus1_ "setFSLabelFd" $
+                ioctl fd (#const BTRFS_IOC_SET_FSLABEL) buf
+
+-- | Set the label of a btrfs file system. Note that a label can be up to
+-- 255 /bytes/ long. If the provided label is longer, it will be silently
+-- truncated.
+--
+-- Note: calls the @BTRFS_IOC_SET_FSLABEL@ @ioctl@.
+setFSLabel
+    :: FILEPATH -- ^ The mount point of the volume (or any file in that volume).
+    -> FILEPATH -- ^ The new label.
+    -> IO ()
+setFSLabel path label =
+    withFd path ReadOnly $ \fd ->
+        setFSLabelFd fd label
+
+maxLabelSize :: Int
+maxLabelSize = (#const BTRFS_LABEL_SIZE)
+
+--------------------------------------------------------------------------------
+
 syncFd :: Fd -> IO ()
 syncFd fd =
     throwErrnoIfMinus1_ "syncFd" $
@@ -888,7 +1006,7 @@
         count      <- (#peek struct btrfs_data_container, elem_cnt   ) fspath :: IO Word32
         let val = (#ptr struct btrfs_data_container, val) fspath :: Ptr Word64
         vals <- peekArray (fromIntegral count) val
-        paths <- mapM (peekCString . plusPtr val . fromIntegral) vals
+        paths <- mapM (peekFilePath . plusPtr val . fromIntegral) vals
         return (paths, fromIntegral elemMissed)
   where
     fspathSize = 2 * 1024 + (#size struct btrfs_data_container)
@@ -917,7 +1035,7 @@
             ioctl_fast fd (#const BTRFS_IOC_INO_LOOKUP) ila
         treeId' <- (#peek struct btrfs_ioctl_ino_lookup_args, treeid) ila :: IO Word64
         let cName = (#ptr struct btrfs_ioctl_ino_lookup_args, name) ila
-        name <- peekCString cName
+        name <- peekFilePath cName
         return (treeId', dropTrailingSlash name)
 
 -- | Find the path of a file given its inode number and the id of the
@@ -1122,7 +1240,7 @@
     LE64 dirId   <- (#peek struct btrfs_root_ref, dirid   ) rrPtr
     LE16 nameLen <- (#peek struct btrfs_root_ref, name_len) rrPtr
     let cName = rrPtr `plusPtr` (#size struct btrfs_root_ref)
-    name <- peekCStringLen (cName, fromIntegral nameLen)
+    name <- peekFilePathLen (cName, fromIntegral nameLen)
     return (dirId, name)
 
 --------------------------------------------------------------------------------
@@ -1134,19 +1252,13 @@
 
 withSplitPathOpenParent :: String -> Int -> FILEPATH -> (CStringLen -> Fd -> IO r) -> IO r
 withSplitPathOpenParent loc maxLen path action =
-    unsafeWithCStringLen name $ \cName @ (_, l) -> do
+    unsafeWithFilePathLen name $ \cName @ (_, l) -> do
         unless (l <= maxLen) $
             ioError $ flip ioeSetErrorString "the subvolume name is too long"
                     $ mkIOError illegalOperationErrorType loc Nothing (Just (asString name))
         withFd dir ReadOnly $ action cName
   where
     (dir, name) = splitFileName (dropTrailingSlash path)
-
-withBlockSIGVTALRM :: IO a -> IO a
-withBlockSIGVTALRM =
-    bracket_ (blockSignals s) (unblockSignals s)
-  where
-    s = addSignal sigVTALRM emptySignalSet
 
 nothingIf :: Bool -> a -> Maybe a
 nothingIf f v = if f then Nothing else Just v
diff --git a/System/Linux/Btrfs/FilePathLike.hs b/System/Linux/Btrfs/FilePathLike.hs
--- a/System/Linux/Btrfs/FilePathLike.hs
+++ b/System/Linux/Btrfs/FilePathLike.hs
@@ -7,29 +7,29 @@
 
 import Data.String
 import Data.Monoid
-import Data.List
-import Foreign.C.String hiding
-    ( peekCString, peekCStringLen
-    , newCString, newCStringLen
-    , withCString, withCStringLen)
-import qualified Foreign.C.String as S
+import Data.List (dropWhileEnd)
+import Foreign.C.String (CString, CStringLen)
+import qualified System.Posix.Internals as P
+import GHC.IO.Encoding (getFileSystemEncoding)
+import qualified GHC.Foreign as GHC
 import qualified Data.ByteString as B
 import qualified Data.ByteString.Unsafe as B
 import qualified Data.ByteString.Char8 as B8
-import System.Posix.Types
+import System.Posix.Types (Fd, FileMode)
 import System.Posix.IO hiding (openFd)
 import System.Posix.ByteString.FilePath (RawFilePath)
 import qualified System.Posix.IO as S (openFd)
 import qualified System.Posix.IO.ByteString as B (openFd)
 import System.IO.Unsafe (unsafePerformIO)
+import Prelude
 
 class (Monoid s, IsString s) => FilePathLike s where
     asString :: s -> String
-    peekCString :: CString -> IO s
-    peekCStringLen :: CStringLen -> IO s
-    withCString :: s -> (CString -> IO a) -> IO a 
-    withCStringLen :: s -> (CStringLen -> IO a) -> IO a 
-    unsafeWithCStringLen :: s -> (CStringLen -> IO a) -> IO a 
+    peekFilePath :: CString -> IO s
+    peekFilePathLen :: CStringLen -> IO s
+    withFilePath :: s -> (CString -> IO a) -> IO a
+    withFilePathLen :: s -> (CStringLen -> IO a) -> IO a
+    unsafeWithFilePathLen :: s -> (CStringLen -> IO a) -> IO a
     openFd :: s -> OpenMode -> Maybe FileMode -> OpenFileFlags -> IO Fd
     dropTrailingSlash :: s -> s
     (</>) :: s -> s -> s
@@ -37,11 +37,13 @@
 
 instance FilePathLike [Char] where
     asString = id
-    peekCString = S.peekCString
-    peekCStringLen = S.peekCStringLen
-    withCString = S.withCString
-    withCStringLen = S.withCStringLen
-    unsafeWithCStringLen = withCStringLen
+    peekFilePath = P.peekFilePath
+    peekFilePathLen = P.peekFilePathLen
+    withFilePath = P.withFilePath
+    withFilePathLen path action =
+        getFileSystemEncoding >>= \enc ->
+            GHC.withCStringLen enc path action
+    unsafeWithFilePathLen = withFilePathLen
     openFd = S.openFd
     dropTrailingSlash s = if null s' then "/" else s'
       where
@@ -58,11 +60,11 @@
 
 instance FilePathLike B.ByteString where
     asString = convert
-    peekCString = B.packCString
-    peekCStringLen = B.packCStringLen
-    withCString = B.useAsCString
-    withCStringLen = B.useAsCStringLen
-    unsafeWithCStringLen = B.unsafeUseAsCStringLen
+    peekFilePath = B.packCString
+    peekFilePathLen = B.packCStringLen
+    withFilePath = B.useAsCString
+    withFilePathLen = B.useAsCStringLen
+    unsafeWithFilePathLen = B.unsafeUseAsCStringLen
     openFd = B.openFd
     dropTrailingSlash s = if B.null s' then slashBS else s'
       where
@@ -81,7 +83,7 @@
         curDir = B8.pack "./"
 
 convert :: (FilePathLike s1, FilePathLike s2) => s1 -> s2
-convert s = unsafePerformIO $ unsafeWithCStringLen s peekCStringLen
+convert s = unsafePerformIO $ unsafeWithFilePathLen s peekFilePathLen
 
 slashBS :: B.ByteString
 slashBS = B8.singleton '/'
diff --git a/btrfs.cabal b/btrfs.cabal
--- a/btrfs.cabal
+++ b/btrfs.cabal
@@ -1,5 +1,5 @@
 name:                btrfs
-version:             0.1.2.3
+version:             0.2.0.0
 synopsis:            Bindings to the btrfs API
 description:
   This package provides bindings to the low-level btrfs API (i.e. the
@@ -23,7 +23,7 @@
 cabal-version:       >=1.10
 
 extra-source-files:
-  ChangeLog
+  ChangeLog.md
   include/btrfs/ctree.h
   include/btrfs/extent-cache.h
   include/btrfs/extent_io.h
@@ -32,6 +32,7 @@
   include/btrfs/list.h
   include/btrfs/radix-tree.h
   include/btrfs/rbtree.h
+  include/btrfs/sizes.h
   include/sys/capability.h
   make-bytestring.hs
 
@@ -64,8 +65,8 @@
   else
     build-depends:       base >=4.6 && <5, btrfs, unix, filepath,
                          linux-file-extents, ansi-terminal
-    default-language:    Haskell2010
-    ghc-options:         -Wall
+  default-language:    Haskell2010
+  ghc-options:         -Wall -threaded
 
 executable btrfs-clone-range
   hs-source-dirs:      examples
@@ -74,8 +75,8 @@
     buildable:           False
   else
     build-depends:       base >=4.6 && <5, btrfs
-    default-language:    Haskell2010
-    ghc-options:         -Wall
+  default-language:    Haskell2010
+  ghc-options:         -Wall
 
 executable btrfs-split
   hs-source-dirs:      examples
@@ -84,9 +85,19 @@
     buildable:           False
   else
     build-depends:       base >=4.6 && <5, btrfs, unix
-    default-language:    Haskell2010
-    ghc-options:         -Wall
+  default-language:    Haskell2010
+  ghc-options:         -Wall
 
+executable btrfs-join
+  hs-source-dirs:      examples
+  main-is:             btrfs-join.hs
+  if !flag(examples)
+    buildable:           False
+  else
+    build-depends:       base >=4.6 && <5, btrfs, unix
+  default-language:    Haskell2010
+  ghc-options:         -Wall
+
 executable btrfs-list-subvols
   hs-source-dirs:      examples
   main-is:             btrfs-list-subvols.hs
@@ -94,8 +105,8 @@
     buildable:           False
   else
     build-depends:       base >=4.6 && <5, btrfs
-    default-language:    Haskell2010
-    ghc-options:         -Wall
+  default-language:    Haskell2010
+  ghc-options:         -Wall
 
 executable btrfs-print-creation-time
   hs-source-dirs:      examples
@@ -105,5 +116,5 @@
     buildable:           False
   else
     build-depends:       base >=4.6 && <5, btrfs, unix >=2.6, time >=1.4
-    default-language:    Haskell2010
-    ghc-options:         -Wall
+  default-language:    Haskell2010
+  ghc-options:         -Wall
diff --git a/examples/btrfs-join.hs b/examples/btrfs-join.hs
new file mode 100644
--- /dev/null
+++ b/examples/btrfs-join.hs
@@ -0,0 +1,38 @@
+import System.Environment (getArgs, getProgName)
+import System.Exit (exitFailure)
+import System.IO (stderr, hPutStrLn)
+import Control.Exception (bracket)
+import System.Posix
+
+import System.Linux.Btrfs (cloneRangeFd)
+
+main :: IO ()
+main = do
+    args <- getArgs
+    case args of
+        dstPath : srcFiles0@(_ : _) ->
+            withWriteFd dstPath $ \dstFd -> do
+                let loop offset (srcFile : srcFiles) = do
+                        len <- withReadFd srcFile $ \srcFd -> do
+                            cloneRangeFd srcFd 0 0 dstFd offset
+                            fileSize <$> getFdStatus srcFd
+                        loop (offset + fromIntegral len) srcFiles
+                    loop _ [] = return ()
+                loop 0 srcFiles0
+        _ -> do
+            prog <- getProgName
+            hPutStrLn stderr "Invalid command line arguments"
+            hPutStrLn stderr $ "Usage: " ++ prog ++ " DEST SOURCE [SOURCE]..."
+            exitFailure
+
+withReadFd :: FilePath -> (Fd -> IO r) -> IO r
+withReadFd path action =
+    bracket
+        (openFd path ReadOnly Nothing defaultFileFlags {nonBlock = True})
+        closeFd action
+
+withWriteFd :: FilePath -> (Fd -> IO r) -> IO r
+withWriteFd path action =
+    bracket
+        (openFd path WriteOnly (Just stdFileMode) defaultFileFlags {trunc = True})
+        closeFd action
diff --git a/include/btrfs/ctree.h b/include/btrfs/ctree.h
--- a/include/btrfs/ctree.h
+++ b/include/btrfs/ctree.h
@@ -19,6 +19,8 @@
 #ifndef __BTRFS_CTREE_H__
 #define __BTRFS_CTREE_H__
 
+#include <stdbool.h>
+
 #if BTRFS_FLAT_INCLUDES
 #include "list.h"
 #include "kerncompat.h"
@@ -26,6 +28,7 @@
 #include "extent-cache.h"
 #include "extent_io.h"
 #include "ioctl.h"
+#include "sizes.h"
 #else
 #include <btrfs/list.h>
 #include <btrfs/kerncompat.h>
@@ -33,6 +36,7 @@
 #include <btrfs/extent-cache.h>
 #include <btrfs/extent_io.h>
 #include <btrfs/ioctl.h>
+#include <btrfs/sizes.h>
 #endif /* BTRFS_FLAT_INCLUDES */
 
 struct btrfs_root;
@@ -40,6 +44,14 @@
 struct btrfs_free_space_ctl;
 #define BTRFS_MAGIC 0x4D5F53665248425FULL /* ascii _BHRfS_M, no null */
 
+/*
+ * Fake signature for an unfinalized filesystem, which only has barebone tree
+ * structures (normally 6 near empty trees, on SINGLE meta/sys temporary chunks)
+ *
+ * ascii !BHRfS_M, no null
+ */
+#define BTRFS_MAGIC_TEMPORARY 0x4D5F536652484221ULL
+
 #define BTRFS_MAX_MIRRORS 3
 
 #define BTRFS_MAX_LEVEL 8
@@ -79,6 +91,9 @@
 /* tracks free space in block groups. */
 #define BTRFS_FREE_SPACE_TREE_OBJECTID 10ULL
 
+/* device stats in the device tree */
+#define BTRFS_DEV_STATS_OBJECTID 0ULL
+
 /* for storing balance parameters in the root tree */
 #define BTRFS_BALANCE_OBJECTID -4ULL
 
@@ -127,6 +142,8 @@
  */
 #define BTRFS_DEV_ITEMS_OBJECTID 1ULL
 
+#define BTRFS_EMPTY_SUBVOL_DIR_OBJECTID 2ULL
+
 /*
  * the max metadata block size.  This limit is somewhat artificial,
  * but the memmove costs go through the roof for larger blocks.
@@ -152,10 +169,9 @@
 /* csum types */
 #define BTRFS_CSUM_TYPE_CRC32	0
 
+/* four bytes for CRC32 */
 static int btrfs_csum_sizes[] = { 4 };
 
-/* four bytes for CRC32 */
-#define BTRFS_CRC32_SIZE 4
 #define BTRFS_EMPTY_DIR_SIZE 0
 
 #define BTRFS_FT_UNKNOWN	0
@@ -341,18 +357,9 @@
 	u8 level;
 } __attribute__ ((__packed__));
 
-#define BTRFS_NODEPTRS_PER_BLOCK(r) (((r)->nodesize - \
-			        sizeof(struct btrfs_header)) / \
-			        sizeof(struct btrfs_key_ptr))
 #define __BTRFS_LEAF_DATA_SIZE(bs) ((bs) - sizeof(struct btrfs_header))
-#define BTRFS_LEAF_DATA_SIZE(r) (__BTRFS_LEAF_DATA_SIZE(r->nodesize))
-#define BTRFS_MAX_INLINE_DATA_SIZE(r) (BTRFS_LEAF_DATA_SIZE(r) - \
-					sizeof(struct btrfs_item) - \
-					sizeof(struct btrfs_file_extent_item))
-#define BTRFS_MAX_XATTR_SIZE(r)	(BTRFS_LEAF_DATA_SIZE(r) - \
-				 sizeof(struct btrfs_item) -\
-				 sizeof(struct btrfs_dir_item))
-
+#define BTRFS_LEAF_DATA_SIZE(fs_info) \
+				(__BTRFS_LEAF_DATA_SIZE(fs_info->nodesize))
 
 /*
  * this is a very generous portion of the super block, giving us
@@ -429,7 +436,7 @@
 	__le32 sectorsize;
 	__le32 nodesize;
 	/* Unused and must be equal to nodesize */
-	__le32 leafsize;
+	__le32 __unused_leafsize;
 	__le32 stripesize;
 	__le32 sys_chunk_array_size;
 	__le64 chunk_root_generation;
@@ -458,19 +465,20 @@
  * ones specified below then we will fail to mount
  */
 #define BTRFS_FEATURE_COMPAT_RO_FREE_SPACE_TREE	(1ULL << 0)
+/*
+ * Older kernels on big-endian systems produced broken free space tree bitmaps,
+ * and btrfs-progs also used to corrupt the free space tree. If this bit is
+ * clear, then the free space tree cannot be trusted. btrfs-progs can also
+ * intentionally clear this bit to ask the kernel to rebuild the free space
+ * tree.
+ */
+#define BTRFS_FEATURE_COMPAT_RO_FREE_SPACE_TREE_VALID	(1ULL << 1)
 
 #define BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF	(1ULL << 0)
 #define BTRFS_FEATURE_INCOMPAT_DEFAULT_SUBVOL	(1ULL << 1)
 #define BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS	(1ULL << 2)
 #define BTRFS_FEATURE_INCOMPAT_COMPRESS_LZO	(1ULL << 3)
-
-/*
- * some patches floated around with a second compression method
- * lets save that incompat here for when they do get in
- * Note we don't actually support it, we're just reserving the
- * number
- */
-#define BTRFS_FEATURE_INCOMPAT_COMPRESS_LZOv2   (1ULL << 4)
+#define BTRFS_FEATURE_INCOMPAT_COMPRESS_ZSTD	(1ULL << 4)
 
 /*
  * older kernels tried to do bigger metadata blocks, but the
@@ -484,13 +492,18 @@
 
 #define BTRFS_FEATURE_COMPAT_SUPP		0ULL
 
-#define BTRFS_FEATURE_COMPAT_RO_SUPP			\
-	(BTRFS_FEATURE_COMPAT_RO_FREE_SPACE_TREE)
+/*
+ * The FREE_SPACE_TREE and FREE_SPACE_TREE_VALID compat_ro bits must not be
+ * added here until read-write support for the free space tree is implemented in
+ * btrfs-progs.
+ */
+#define BTRFS_FEATURE_COMPAT_RO_SUPP		0ULL
 
 #define BTRFS_FEATURE_INCOMPAT_SUPP			\
 	(BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF |		\
 	 BTRFS_FEATURE_INCOMPAT_DEFAULT_SUBVOL |	\
 	 BTRFS_FEATURE_INCOMPAT_COMPRESS_LZO |		\
+	 BTRFS_FEATURE_INCOMPAT_COMPRESS_ZSTD |		\
 	 BTRFS_FEATURE_INCOMPAT_BIG_METADATA |		\
 	 BTRFS_FEATURE_INCOMPAT_EXTENDED_IREF |		\
 	 BTRFS_FEATURE_INCOMPAT_RAID56 |		\
@@ -543,22 +556,24 @@
  * The slots array records the index of the item or block pointer
  * used while walking the tree.
  */
-
+enum { READA_NONE = 0, READA_BACK, READA_FORWARD };
 struct btrfs_path {
 	struct extent_buffer *nodes[BTRFS_MAX_LEVEL];
 	int slots[BTRFS_MAX_LEVEL];
-	/* if there is real range locking, this locks field will change */
+#if 0
+	/* The kernel locking sheme is not done in userspace. */
 	int locks[BTRFS_MAX_LEVEL];
-	int reada;
+#endif
+	signed char reada;
 	/* keep some upper locks as we walk down */
-	int lowest_level;
+	u8 lowest_level;
 
 	/*
 	 * set by btrfs_split_item, tells search_slot to keep all locks
 	 * and to force calls to keep space in the nodes
 	 */
-	unsigned int search_for_split:1;
-	unsigned int skip_check_block:1;
+	u8 search_for_split;
+	u8 skip_check_block;
 };
 
 /*
@@ -576,9 +591,10 @@
 	__le32 refs;
 } __attribute__ ((__packed__));
 
-#define BTRFS_MAX_EXTENT_ITEM_SIZE(r) ((BTRFS_LEAF_DATA_SIZE(r) >> 4) - \
+#define BTRFS_MAX_EXTENT_ITEM_SIZE(r) \
+			((BTRFS_LEAF_DATA_SIZE(r->fs_info) >> 4) - \
 					sizeof(struct btrfs_item))
-#define BTRFS_MAX_EXTENT_SIZE		(128 * 1024 * 1024)
+#define BTRFS_MAX_EXTENT_SIZE		SZ_128M
 
 #define BTRFS_EXTENT_FLAG_DATA		(1ULL << 0)
 #define BTRFS_EXTENT_FLAG_TREE_BLOCK	(1ULL << 1)
@@ -650,8 +666,9 @@
 	BTRFS_COMPRESS_NONE  = 0,
 	BTRFS_COMPRESS_ZLIB  = 1,
 	BTRFS_COMPRESS_LZO   = 2,
-	BTRFS_COMPRESS_TYPES = 2,
-	BTRFS_COMPRESS_LAST  = 3,
+	BTRFS_COMPRESS_ZSTD  = 3,
+	BTRFS_COMPRESS_TYPES = 3,
+	BTRFS_COMPRESS_LAST  = 4,
 } btrfs_compression_type;
 
 /* we don't understand any encryption methods right now */
@@ -780,6 +797,84 @@
 	__le16 name_len;
 } __attribute__ ((__packed__));
 
+struct btrfs_disk_balance_args {
+	/*
+	 * profiles to operate on, single is denoted by
+	 * BTRFS_AVAIL_ALLOC_BIT_SINGLE
+	 */
+	__le64 profiles;
+
+	/*
+	 * usage filter
+	 * BTRFS_BALANCE_ARGS_USAGE with a single value means '0..N'
+	 * BTRFS_BALANCE_ARGS_USAGE_RANGE - range syntax, min..max
+	 */
+	union {
+		__le64 usage;
+		struct {
+			__le32 usage_min;
+			__le32 usage_max;
+		};
+	};
+
+	/* devid filter */
+	__le64 devid;
+
+	/* devid subset filter [pstart..pend) */
+	__le64 pstart;
+	__le64 pend;
+
+	/* btrfs virtual address space subset filter [vstart..vend) */
+	__le64 vstart;
+	__le64 vend;
+
+	/*
+	 * profile to convert to, single is denoted by
+	 * BTRFS_AVAIL_ALLOC_BIT_SINGLE
+	 */
+	__le64 target;
+
+	/* BTRFS_BALANCE_ARGS_* */
+	__le64 flags;
+
+	/*
+	 * BTRFS_BALANCE_ARGS_LIMIT with value 'limit'
+	 * BTRFS_BALANCE_ARGS_LIMIT_RANGE - the extend version can use minimum
+	 * and maximum
+	 */
+	union {
+		__le64 limit;
+		struct {
+			__le32 limit_min;
+			__le32 limit_max;
+		};
+	};
+
+	/*
+	 * Process chunks that cross stripes_min..stripes_max devices,
+	 * BTRFS_BALANCE_ARGS_STRIPES_RANGE
+	 */
+	__le32 stripes_min;
+	__le32 stripes_max;
+
+	__le64 unused[6];
+} __attribute__ ((__packed__));
+
+/*
+ * store balance parameters to disk so that balance can be properly
+ * resumed after crash or unmount
+ */
+struct btrfs_balance_item {
+	/* BTRFS_BALANCE_* */
+	__le64 flags;
+
+	struct btrfs_disk_balance_args data;
+	struct btrfs_disk_balance_args meta;
+	struct btrfs_disk_balance_args sys;
+
+	__le64 unused[4];
+} __attribute__ ((__packed__));
+
 #define BTRFS_FILE_EXTENT_INLINE 0
 #define BTRFS_FILE_EXTENT_REG 1
 #define BTRFS_FILE_EXTENT_PREALLOC 2
@@ -833,6 +928,14 @@
 
 } __attribute__ ((__packed__));
 
+struct btrfs_dev_stats_item {
+        /*
+         * grow this item struct at the end for future enhancements and keep
+         * the existing values unchanged
+         */
+        __le64 values[BTRFS_DEV_STAT_VALUES_MAX];
+} __attribute__ ((__packed__));
+
 struct btrfs_csum_item {
 	u8 csum;
 } __attribute__ ((__packed__));
@@ -843,7 +946,7 @@
  *  - the first 64k blank is useful for some boot loader/manager
  *  - the first 1M could be scratched by buggy partitioner or somesuch
  */
-#define BTRFS_BLOCK_RESERVED_1M_FOR_SUPER	((u64)1024 * 1024)
+#define BTRFS_BLOCK_RESERVED_1M_FOR_SUPER	((u64)SZ_1M)
 
 /* tag for the radix tree of block groups in ram */
 #define BTRFS_BLOCK_GROUP_DATA		(1ULL << 0)
@@ -856,8 +959,18 @@
 #define BTRFS_BLOCK_GROUP_RAID5    	(1ULL << 7)
 #define BTRFS_BLOCK_GROUP_RAID6    	(1ULL << 8)
 #define BTRFS_BLOCK_GROUP_RESERVED	BTRFS_AVAIL_ALLOC_BIT_SINGLE
-#define BTRFS_NR_RAID_TYPES             7
 
+enum btrfs_raid_types {
+	BTRFS_RAID_RAID10,
+	BTRFS_RAID_RAID1,
+	BTRFS_RAID_DUP,
+	BTRFS_RAID_RAID0,
+	BTRFS_RAID_SINGLE,
+	BTRFS_RAID_RAID5,
+	BTRFS_RAID_RAID6,
+	BTRFS_NR_RAID_TYPES
+};
+
 #define BTRFS_BLOCK_GROUP_TYPE_MASK	(BTRFS_BLOCK_GROUP_DATA |    \
 					 BTRFS_BLOCK_GROUP_SYSTEM |  \
 					 BTRFS_BLOCK_GROUP_METADATA)
@@ -1015,8 +1128,8 @@
 
 	struct btrfs_fs_devices *fs_devices;
 	struct list_head space_info;
-	int system_allocs;
 
+	unsigned int system_allocs:1;
 	unsigned int readonly:1;
 	unsigned int on_restoring:1;
 	unsigned int is_chunk_recover:1;
@@ -1026,15 +1139,21 @@
 	unsigned int ignore_chunk_tree_error:1;
 	unsigned int avoid_meta_chunk_alloc:1;
 	unsigned int avoid_sys_chunk_alloc:1;
+	unsigned int finalize_on_close:1;
 
-	int (*free_extent_hook)(struct btrfs_trans_handle *trans,
-				struct btrfs_root *root,
+	int transaction_aborted;
+
+	int (*free_extent_hook)(struct btrfs_fs_info *fs_info,
 				u64 bytenr, u64 num_bytes, u64 parent,
 				u64 root_objectid, u64 owner, u64 offset,
 				int refs_to_drop);
 	struct cache_tree *fsck_extent_cache;
 	struct cache_tree *corrupt_blocks;
 
+	/* Cached block sizes */
+	u32 nodesize;
+	u32 sectorsize;
+	u32 stripesize;
 };
 
 /*
@@ -1050,24 +1169,11 @@
 	u64 objectid;
 	u64 last_trans;
 
-	/* data allocations are done in sectorsize units */
-	u32 sectorsize;
-
-	/* node allocations are done in nodesize units */
-	u32 nodesize;
-
-	/* Unused, equal to nodesize */
-	u32 leafsize;
-
-	/* leaf allocations are done in nodesize units */
-	u32 stripesize;
-
 	int ref_cows;
 	int track_dirty;
 
 
 	u32 type;
-	u64 highest_inode;
 	u64 last_inode_alloc;
 
 	/*
@@ -1085,6 +1191,35 @@
 	struct rb_node rb_node;
 };
 
+static inline u32 BTRFS_MAX_ITEM_SIZE(const struct btrfs_fs_info *info)
+{
+	return BTRFS_LEAF_DATA_SIZE(info) - sizeof(struct btrfs_item);
+}
+
+static inline u32 BTRFS_NODEPTRS_PER_BLOCK(const struct btrfs_fs_info *info)
+{
+	return BTRFS_LEAF_DATA_SIZE(info) / sizeof(struct btrfs_key_ptr);
+}
+
+static inline u32 BTRFS_NODEPTRS_PER_EXTENT_BUFFER(const struct extent_buffer *eb)
+{
+	BUG_ON(eb->fs_info && eb->fs_info->nodesize != eb->len);
+	return __BTRFS_LEAF_DATA_SIZE(eb->len) / sizeof(struct btrfs_key_ptr);
+}
+
+#define BTRFS_FILE_EXTENT_INLINE_DATA_START		\
+	(offsetof(struct btrfs_file_extent_item, disk_bytenr))
+static inline u32 BTRFS_MAX_INLINE_DATA_SIZE(const struct btrfs_fs_info *info)
+{
+	return BTRFS_MAX_ITEM_SIZE(info) -
+		BTRFS_FILE_EXTENT_INLINE_DATA_START;
+}
+
+static inline u32 BTRFS_MAX_XATTR_SIZE(const struct btrfs_fs_info *info)
+{
+	return BTRFS_MAX_ITEM_SIZE(info) - sizeof(struct btrfs_dir_item);
+}
+
 /*
  * inode items have the data typically returned from stat and store other
  * info about object characteristics.  There is one for every file and dir in
@@ -1205,12 +1340,44 @@
 #define BTRFS_QGROUP_RELATION_KEY	246
 
 /*
- * Persistently stores the io stats in the device tree.
- * One key for all stats, (0, BTRFS_DEV_STATS_KEY, devid).
+ * Obsolete name, see BTRFS_TEMPORARY_ITEM_KEY.
  */
-#define BTRFS_DEV_STATS_KEY	249
+#define BTRFS_BALANCE_ITEM_KEY	248
 
 /*
+ * The key type for tree items that are stored persistently, but do not need to
+ * exist for extended period of time. The items can exist in any tree.
+ *
+ * [subtype, BTRFS_TEMPORARY_ITEM_KEY, data]
+ *
+ * Existing items:
+ *
+ * - balance status item
+ *   (BTRFS_BALANCE_OBJECTID, BTRFS_TEMPORARY_ITEM_KEY, 0)
+ */
+#define BTRFS_TEMPORARY_ITEM_KEY	248
+
+/*
+ * Obsolete name, see BTRFS_PERSISTENT_ITEM_KEY
+ */
+#define BTRFS_DEV_STATS_KEY		249
+
+/*
+ * The key type for tree items that are stored persistently and usually exist
+ * for a long period, eg. filesystem lifetime. The item kinds can be status
+ * information, stats or preference values. The item can exist in any tree.
+ *
+ * [subtype, BTRFS_PERSISTENT_ITEM_KEY, data]
+ *
+ * Existing items:
+ *
+ * - device statistics, store IO stats in the device tree, one key for all
+ *   stats
+ *   (BTRFS_DEV_STATS_OBJECTID, BTRFS_DEV_STATS_KEY, 0)
+ */
+#define BTRFS_PERSISTENT_ITEM_KEY	249
+
+/*
  * Persistently stores the device replace state in the device tree.
  * The key is built like this: (0, BTRFS_DEV_REPLACE_KEY, 0).
  */
@@ -1240,6 +1407,15 @@
 #define BTRFS_INODE_NODATASUM		(1 << 0)
 #define BTRFS_INODE_NODATACOW		(1 << 1)
 #define BTRFS_INODE_READONLY		(1 << 2)
+#define BTRFS_INODE_NOCOMPRESS		(1 << 3)
+#define BTRFS_INODE_PREALLOC		(1 << 4)
+#define BTRFS_INODE_SYNC		(1 << 5)
+#define BTRFS_INODE_IMMUTABLE		(1 << 6)
+#define BTRFS_INODE_APPEND		(1 << 7)
+#define BTRFS_INODE_NODUMP		(1 << 8)
+#define BTRFS_INODE_NOATIME		(1 << 9)
+#define BTRFS_INODE_DIRSYNC		(1 << 10)
+#define BTRFS_INODE_COMPRESS		(1 << 11)
 
 #define read_eb_member(eb, ptr, type, member, result) (			\
 	read_extent_buffer(eb, (char *)(result),			\
@@ -1697,7 +1873,7 @@
 	return btrfs_item_end(eb, btrfs_item_nr(nr));
 }
 
-static inline u32 btrfs_item_offset_nr(struct extent_buffer *eb, int nr)
+static inline u32 btrfs_item_offset_nr(const struct extent_buffer *eb, int nr)
 {
 	return btrfs_item_offset(eb, btrfs_item_nr(nr));
 }
@@ -1740,7 +1916,10 @@
 BTRFS_SETGET_FUNCS(dir_name_len, struct btrfs_dir_item, name_len, 16);
 BTRFS_SETGET_FUNCS(dir_transid, struct btrfs_dir_item, transid, 64);
 
+BTRFS_SETGET_STACK_FUNCS(stack_dir_data_len, struct btrfs_dir_item, data_len, 16);
+BTRFS_SETGET_STACK_FUNCS(stack_dir_type, struct btrfs_dir_item, type, 8);
 BTRFS_SETGET_STACK_FUNCS(stack_dir_name_len, struct btrfs_dir_item, name_len, 16);
+BTRFS_SETGET_STACK_FUNCS(stack_dir_transid, struct btrfs_dir_item, transid, 64);
 
 static inline void btrfs_dir_item_key(struct extent_buffer *eb,
 				      struct btrfs_dir_item *item,
@@ -1825,17 +2004,6 @@
 	btrfs_disk_key_to_cpu(key, &disk_key);
 }
 
-
-static inline u8 btrfs_key_type(struct btrfs_key *key)
-{
-	return key->type;
-}
-
-static inline void btrfs_set_key_type(struct btrfs_key *key, u8 val)
-{
-	key->type = val;
-}
-
 /* struct btrfs_header */
 BTRFS_SETGET_HEADER_FUNCS(header_bytenr, struct btrfs_header, bytenr, 64);
 BTRFS_SETGET_HEADER_FUNCS(header_generation, struct btrfs_header,
@@ -1895,33 +2063,12 @@
 	return offsetof(struct btrfs_header, chunk_tree_uuid);
 }
 
-static inline u8 *btrfs_super_fsid(struct extent_buffer *eb)
-{
-	unsigned long ptr = offsetof(struct btrfs_super_block, fsid);
-	return (u8 *)ptr;
-}
-
 static inline u8 *btrfs_header_csum(struct extent_buffer *eb)
 {
 	unsigned long ptr = offsetof(struct btrfs_header, csum);
 	return (u8 *)ptr;
 }
 
-static inline struct btrfs_node *btrfs_buffer_node(struct extent_buffer *eb)
-{
-	return NULL;
-}
-
-static inline struct btrfs_leaf *btrfs_buffer_leaf(struct extent_buffer *eb)
-{
-	return NULL;
-}
-
-static inline struct btrfs_header *btrfs_buffer_header(struct extent_buffer *eb)
-{
-	return NULL;
-}
-
 static inline int btrfs_is_leaf(struct extent_buffer *eb)
 {
 	return (btrfs_header_level(eb) == 0);
@@ -1956,6 +2103,38 @@
 BTRFS_SETGET_STACK_FUNCS(root_rtransid, struct btrfs_root_item,
 			 rtransid, 64);
 
+static inline struct btrfs_timespec* btrfs_root_ctime(
+		struct btrfs_root_item *root_item)
+{
+	unsigned long ptr = (unsigned long)root_item;
+	ptr += offsetof(struct btrfs_root_item, ctime);
+	return (struct btrfs_timespec *)ptr;
+}
+
+static inline struct btrfs_timespec* btrfs_root_otime(
+		struct btrfs_root_item *root_item)
+{
+	unsigned long ptr = (unsigned long)root_item;
+	ptr += offsetof(struct btrfs_root_item, otime);
+	return (struct btrfs_timespec *)ptr;
+}
+
+static inline struct btrfs_timespec* btrfs_root_stime(
+		struct btrfs_root_item *root_item)
+{
+	unsigned long ptr = (unsigned long)root_item;
+	ptr += offsetof(struct btrfs_root_item, stime);
+	return (struct btrfs_timespec *)ptr;
+}
+
+static inline struct btrfs_timespec* btrfs_root_rtime(
+		struct btrfs_root_item *root_item)
+{
+	unsigned long ptr = (unsigned long)root_item;
+	ptr += offsetof(struct btrfs_root_item, rtime);
+	return (struct btrfs_timespec *)ptr;
+}
+
 /* struct btrfs_root_backup */
 BTRFS_SETGET_STACK_FUNCS(backup_tree_root, struct btrfs_root_backup,
 		   tree_root, 64);
@@ -2036,8 +2215,6 @@
 			 sectorsize, 32);
 BTRFS_SETGET_STACK_FUNCS(super_nodesize, struct btrfs_super_block,
 			 nodesize, 32);
-BTRFS_SETGET_STACK_FUNCS(super_leafsize, struct btrfs_super_block,
-			 leafsize, 32);
 BTRFS_SETGET_STACK_FUNCS(super_stripesize, struct btrfs_super_block,
 			 stripesize, 32);
 BTRFS_SETGET_STACK_FUNCS(super_root_dir, struct btrfs_super_block,
@@ -2183,7 +2360,50 @@
 BTRFS_SETGET_STACK_FUNCS(stack_qgroup_limit_rsv_exclusive,
 			 struct btrfs_qgroup_limit_item, rsv_exclusive, 64);
 
+/* btrfs_balance_item */
+BTRFS_SETGET_FUNCS(balance_item_flags, struct btrfs_balance_item, flags, 64);
+
+static inline struct btrfs_disk_balance_args* btrfs_balance_item_data(
+		struct extent_buffer *eb, struct btrfs_balance_item *bi)
+{
+	unsigned long offset = (unsigned long)bi;
+	struct btrfs_balance_item *p;
+	p = (struct btrfs_balance_item *)(eb->data + offset);
+	return &p->data;
+}
+
+static inline struct btrfs_disk_balance_args* btrfs_balance_item_meta(
+		struct extent_buffer *eb, struct btrfs_balance_item *bi)
+{
+	unsigned long offset = (unsigned long)bi;
+	struct btrfs_balance_item *p;
+	p = (struct btrfs_balance_item *)(eb->data + offset);
+	return &p->meta;
+}
+
+static inline struct btrfs_disk_balance_args* btrfs_balance_item_sys(
+		struct extent_buffer *eb, struct btrfs_balance_item *bi)
+{
+	unsigned long offset = (unsigned long)bi;
+	struct btrfs_balance_item *p;
+	p = (struct btrfs_balance_item *)(eb->data + offset);
+	return &p->sys;
+}
+
 /*
+ * btrfs_dev_stats_item helper, returns pointer to the raw array, do the
+ * endiannes conversion, @dsi is offset to eb data
+ */
+static inline __le64* btrfs_dev_stats_values(struct extent_buffer *eb,
+		struct btrfs_dev_stats_item *dsi)
+{
+	unsigned long offset = (unsigned long)dsi;
+	struct btrfs_dev_stats_item *p;
+	p = (struct btrfs_dev_stats_item *)(eb->data + offset);
+	return p->values;
+}
+
+/*
  * this returns the number of bytes used by the item on disk, minus the
  * size of any extent headers.  If a file is compressed on disk, this is
  * the compressed size
@@ -2222,47 +2442,20 @@
 	return get_unaligned_32(&sh->len);
 }
 
-/* this returns the number of file bytes represented by the inline item.
- * If an item is compressed, this is the uncompressed size
- */
-static inline u32 btrfs_file_extent_inline_len(struct extent_buffer *eb,
-					       int slot,
-					       struct btrfs_file_extent_item *fi)
-{
-	/*
-	 * return the space used on disk if this item isn't
-	 * compressed or encoded
-	 */
-	if (btrfs_file_extent_compression(eb, fi) == 0 &&
-	    btrfs_file_extent_encryption(eb, fi) == 0 &&
-	    btrfs_file_extent_other_encoding(eb, fi) == 0) {
-		return btrfs_file_extent_inline_item_len(eb,
-							 btrfs_item_nr(slot));
-	}
-
-	/* otherwise use the ram bytes field */
-	return btrfs_file_extent_ram_bytes(eb, fi);
-}
-
-/*
- * NOTE: Backward compatibility, do not use.
- * Replacement: read nodesize directly
- */
-__attribute__((deprecated))
-static inline u32 btrfs_level_size(struct btrfs_root *root, int level) {
-	if (level == 0)
-		return root->leafsize;
-	return root->nodesize;
-}
+#define btrfs_fs_incompat(fs_info, opt) \
+	__btrfs_fs_incompat((fs_info), BTRFS_FEATURE_INCOMPAT_##opt)
 
-static inline int btrfs_fs_incompat(struct btrfs_fs_info *fs_info, u64 flag)
+static inline bool __btrfs_fs_incompat(struct btrfs_fs_info *fs_info, u64 flag)
 {
 	struct btrfs_super_block *disk_super;
 	disk_super = fs_info->super_copy;
 	return !!(btrfs_super_incompat_flags(disk_super) & flag);
 }
 
-static inline int btrfs_fs_compat_ro(struct btrfs_fs_info *fs_info, u64 flag)
+#define btrfs_fs_compat_ro(fs_info, opt) \
+	__btrfs_fs_compat_ro((fs_info), BTRFS_FEATURE_COMPAT_RO_##opt)
+
+static inline int __btrfs_fs_compat_ro(struct btrfs_fs_info *fs_info, u64 flag)
 {
 	struct btrfs_super_block *disk_super;
 	disk_super = fs_info->super_copy;
@@ -2283,14 +2476,12 @@
 			 struct btrfs_root *root,
 			 u64 num_bytes, u64 empty_size,
 			 u64 hint_byte, u64 search_end,
-			 struct btrfs_key *ins, int data);
-int btrfs_fix_block_accounting(struct btrfs_trans_handle *trans,
-				 struct btrfs_root *root);
+			 struct btrfs_key *ins, bool is_data);
+int btrfs_fix_block_accounting(struct btrfs_trans_handle *trans);
 void btrfs_pin_extent(struct btrfs_fs_info *fs_info, u64 bytenr, u64 num_bytes);
 void btrfs_unpin_extent(struct btrfs_fs_info *fs_info,
 			u64 bytenr, u64 num_bytes);
-int btrfs_extent_post_op(struct btrfs_trans_handle *trans,
-			 struct btrfs_root *root);
+int btrfs_extent_post_op(struct btrfs_trans_handle *trans);
 struct btrfs_block_group_cache *btrfs_lookup_block_group(struct
 							 btrfs_fs_info *info,
 							 u64 bytenr);
@@ -2302,22 +2493,19 @@
 					u32 blocksize, u64 root_objectid,
 					struct btrfs_disk_key *key, int level,
 					u64 hint, u64 empty_size);
-int btrfs_alloc_extent(struct btrfs_trans_handle *trans,
-		       struct btrfs_root *root,
-		       u64 num_bytes, u64 parent,
-		       u64 root_objectid, u64 ref_generation,
-		       u64 owner, u64 empty_size, u64 hint_byte,
-		       u64 search_end, struct btrfs_key *ins, int data);
 int btrfs_lookup_extent_info(struct btrfs_trans_handle *trans,
-			     struct btrfs_root *root, u64 bytenr,
+			     struct btrfs_fs_info *fs_info, u64 bytenr,
 			     u64 offset, int metadata, u64 *refs, u64 *flags);
-int btrfs_set_block_flags(struct btrfs_trans_handle *trans,
-			  struct btrfs_root *root,
-			  u64 bytenr, int level, u64 flags);
+int btrfs_set_block_flags(struct btrfs_trans_handle *trans, u64 bytenr,
+			  int level, u64 flags);
 int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
 		  struct extent_buffer *buf, int record_parent);
 int btrfs_dec_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
 		  struct extent_buffer *buf, int record_parent);
+int btrfs_free_tree_block(struct btrfs_trans_handle *trans,
+			  struct btrfs_root *root,
+			  struct extent_buffer *buf,
+			  u64 parent, int last_ref);
 int btrfs_free_extent(struct btrfs_trans_handle *trans,
 		      struct btrfs_root *root,
 		      u64 bytenr, u64 num_bytes, u64 parent,
@@ -2341,15 +2529,13 @@
 int btrfs_read_block_groups(struct btrfs_root *root);
 struct btrfs_block_group_cache *
 btrfs_add_block_group(struct btrfs_fs_info *fs_info, u64 bytes_used, u64 type,
-		      u64 chunk_objectid, u64 chunk_offset, u64 size);
+		      u64 chunk_offset, u64 size);
 int btrfs_make_block_group(struct btrfs_trans_handle *trans,
-			   struct btrfs_root *root, u64 bytes_used,
-			   u64 type, u64 chunk_objectid, u64 chunk_offset,
-			   u64 size);
+			   struct btrfs_fs_info *fs_info, u64 bytes_used,
+			   u64 type, u64 chunk_offset, u64 size);
 int btrfs_make_block_groups(struct btrfs_trans_handle *trans,
-			    struct btrfs_root *root);
-int btrfs_update_block_group(struct btrfs_trans_handle *trans,
-			     struct btrfs_root *root, u64 bytenr, u64 num,
+			    struct btrfs_fs_info *fs_info);
+int btrfs_update_block_group(struct btrfs_root *root, u64 bytenr, u64 num,
 			     int alloc, int mark_free);
 int btrfs_record_file_extent(struct btrfs_trans_handle *trans,
 			      struct btrfs_root *root, u64 objectid,
@@ -2364,10 +2550,12 @@
 			  struct btrfs_block_group_cache *cache);
 u64 add_new_free_space(struct btrfs_block_group_cache *block_group,
 		       struct btrfs_fs_info *info, u64 start, u64 end);
+u64 hash_extent_data_ref(u64 root_objectid, u64 owner, u64 offset);
+
 /* ctree.c */
 int btrfs_comp_cpu_keys(struct btrfs_key *k1, struct btrfs_key *k2);
-int btrfs_del_ptr(struct btrfs_trans_handle *trans, struct btrfs_root *root,
-		   struct btrfs_path *path, int level, int slot);
+int btrfs_del_ptr(struct btrfs_root *root, struct btrfs_path *path,
+		int level, int slot);
 enum btrfs_tree_block_status
 btrfs_check_node(struct btrfs_root *root, struct btrfs_disk_key *parent_key,
 		 struct extent_buffer *buf);
@@ -2376,7 +2564,7 @@
 		 struct extent_buffer *buf);
 void reada_for_search(struct btrfs_root *root, struct btrfs_path *path,
 			     int level, int slot, u64 objectid);
-struct extent_buffer *read_node_slot(struct btrfs_root *root,
+struct extent_buffer *read_node_slot(struct btrfs_fs_info *fs_info,
 				   struct extent_buffer *parent, int slot);
 int btrfs_previous_item(struct btrfs_root *root,
 			struct btrfs_path *path, u64 min_objectid,
@@ -2399,11 +2587,9 @@
 		      struct btrfs_root *root,
 		      struct extent_buffer *buf,
 		      struct extent_buffer **cow_ret, u64 new_root_objectid);
-int btrfs_extend_item(struct btrfs_trans_handle *trans, struct btrfs_root
-		      *root, struct btrfs_path *path, u32 data_size);
-int btrfs_truncate_item(struct btrfs_trans_handle *trans,
-			struct btrfs_root *root,
-			struct btrfs_path *path,
+int btrfs_extend_item(struct btrfs_root *root, struct btrfs_path *path,
+		u32 data_size);
+int btrfs_truncate_item(struct btrfs_root *root, struct btrfs_path *path,
 			u32 new_size, int from_end);
 int btrfs_split_item(struct btrfs_trans_handle *trans,
 		     struct btrfs_root *root,
@@ -2458,7 +2644,7 @@
 }
 
 int btrfs_prev_leaf(struct btrfs_root *root, struct btrfs_path *path);
-int btrfs_leaf_free_space(struct btrfs_root *root, struct extent_buffer *leaf);
+int btrfs_leaf_free_space(struct extent_buffer *leaf);
 void btrfs_fixup_low_keys(struct btrfs_root *root, struct btrfs_path *path,
 			  struct btrfs_disk_key *key, int level);
 int btrfs_set_item_key_safe(struct btrfs_root *root, struct btrfs_path *path,
@@ -2476,6 +2662,8 @@
 int btrfs_insert_root(struct btrfs_trans_handle *trans, struct btrfs_root
 		      *root, struct btrfs_key *key, struct btrfs_root_item
 		      *item);
+int btrfs_del_root(struct btrfs_trans_handle *trans, struct btrfs_root *root,
+		   struct btrfs_key *key);
 int btrfs_update_root(struct btrfs_trans_handle *trans, struct btrfs_root
 		      *root, struct btrfs_key *key, struct btrfs_root_item
 		      *item);
@@ -2535,14 +2723,13 @@
 struct btrfs_inode_ref *btrfs_lookup_inode_ref(struct btrfs_trans_handle *trans,
 		struct btrfs_root *root, struct btrfs_path *path,
 		const char *name, int namelen, u64 ino, u64 parent_ino,
-		u64 index, int ins_len);
+		int ins_len);
 int btrfs_del_inode_ref(struct btrfs_trans_handle *trans,
 			struct btrfs_root *root, const char *name, int name_len,
 			u64 ino, u64 parent_ino, u64 *index);
 
 /* file-item.c */
-int btrfs_del_csums(struct btrfs_trans_handle *trans,
-		    struct btrfs_root *root, u64 bytenr, u64 len);
+int btrfs_del_csums(struct btrfs_trans_handle *trans, u64 bytenr, u64 len);
 int btrfs_insert_file_extent(struct btrfs_trans_handle *trans,
 			     struct btrfs_root *root,
 			     u64 objectid, u64 pos, u64 offset,
@@ -2550,7 +2737,7 @@
 			     u64 num_bytes);
 int btrfs_insert_inline_extent(struct btrfs_trans_handle *trans,
 				struct btrfs_root *root, u64 objectid,
-				u64 offset, char *buffer, size_t size);
+				u64 offset, const char *buffer, size_t size);
 int btrfs_csum_file_block(struct btrfs_trans_handle *trans,
 			  struct btrfs_root *root, u64 alloc_end,
 			  u64 bytenr, char *data, size_t len);
@@ -2576,9 +2763,11 @@
 		u64 dir, u64 index);
 int btrfs_new_inode(struct btrfs_trans_handle *trans, struct btrfs_root *root,
 		u64 ino, u32 mode);
+int btrfs_change_inode_flags(struct btrfs_trans_handle *trans,
+			     struct btrfs_root *root, u64 ino, u64 flags);
 int btrfs_add_link(struct btrfs_trans_handle *trans, struct btrfs_root *root,
 		   u64 ino, u64 parent_ino, char *name, int namelen,
-		   u8 type, u64 *index, int add_backref);
+		   u8 type, u64 *index, int add_backref, int ignore_existed);
 int btrfs_unlink(struct btrfs_trans_handle *trans, struct btrfs_root *root,
 		 u64 ino, u64 parent_ino, u64 index, const char *name,
 		 int namelen, int add_orphan);
@@ -2587,6 +2776,8 @@
 			  u64 ino);
 int btrfs_mkdir(struct btrfs_trans_handle *trans, struct btrfs_root *root,
 		char *name, int namelen, u64 parent_ino, u64 *ino, int mode);
+struct btrfs_root *btrfs_mksubvol(struct btrfs_root *root, const char *base,
+				  u64 root_objectid, bool convert);
 
 /* file.c */
 int btrfs_get_extent(struct btrfs_trans_handle *trans,
@@ -2596,4 +2787,7 @@
 int btrfs_punch_hole(struct btrfs_trans_handle *trans,
 		     struct btrfs_root *root,
 		     u64 ino, u64 offset, u64 len);
+int btrfs_read_file(struct btrfs_root *root, u64 ino, u64 start, int len,
+		    char *dest);
+
 #endif
diff --git a/include/btrfs/extent-cache.h b/include/btrfs/extent-cache.h
--- a/include/btrfs/extent-cache.h
+++ b/include/btrfs/extent-cache.h
@@ -106,8 +106,6 @@
  */
 struct cache_extent *lookup_cache_extent2(struct cache_tree *tree,
 					  u64 objectid, u64 start, u64 size);
-int add_cache_extent2(struct cache_tree *tree,
-		      u64 objectid, u64 start, u64 size);
 int insert_cache_extent2(struct cache_tree *tree, struct cache_extent *pe);
 
 /*
diff --git a/include/btrfs/extent_io.h b/include/btrfs/extent_io.h
--- a/include/btrfs/extent_io.h
+++ b/include/btrfs/extent_io.h
@@ -75,6 +75,7 @@
 	struct cache_tree cache;
 	struct list_head lru;
 	u64 cache_size;
+	u64 max_cache_size;
 };
 
 struct extent_state {
@@ -90,14 +91,15 @@
 	struct cache_extent cache_node;
 	u64 start;
 	u64 dev_bytenr;
-	u32 len;
 	struct extent_io_tree *tree;
 	struct list_head lru;
 	struct list_head recow;
+	u32 len;
 	int refs;
 	u32 flags;
 	int fd;
-	char data[];
+	struct btrfs_fs_info *fs_info;
+	char data[] __attribute__((aligned(8)));
 };
 
 static inline void extent_buffer_get(struct extent_buffer *eb)
@@ -106,27 +108,24 @@
 }
 
 void extent_io_tree_init(struct extent_io_tree *tree);
+void extent_io_tree_init_cache_max(struct extent_io_tree *tree,
+				   u64 max_cache_size);
 void extent_io_tree_cleanup(struct extent_io_tree *tree);
-int set_extent_bits(struct extent_io_tree *tree, u64 start,
-		    u64 end, int bits, gfp_t mask);
-int clear_extent_bits(struct extent_io_tree *tree, u64 start,
-		      u64 end, int bits, gfp_t mask);
+int set_extent_bits(struct extent_io_tree *tree, u64 start, u64 end, int bits);
+int clear_extent_bits(struct extent_io_tree *tree, u64 start, u64 end, int bits);
 int find_first_extent_bit(struct extent_io_tree *tree, u64 start,
 			  u64 *start_ret, u64 *end_ret, int bits);
 int test_range_bit(struct extent_io_tree *tree, u64 start, u64 end,
 		   int bits, int filled);
-int set_extent_dirty(struct extent_io_tree *tree, u64 start,
-		     u64 end, gfp_t mask);
-int clear_extent_dirty(struct extent_io_tree *tree, u64 start,
-		       u64 end, gfp_t mask);
+int set_extent_dirty(struct extent_io_tree *tree, u64 start, u64 end);
+int clear_extent_dirty(struct extent_io_tree *tree, u64 start, u64 end);
 static inline int set_extent_buffer_uptodate(struct extent_buffer *eb)
 {
 	eb->flags |= EXTENT_UPTODATE;
 	return 0;
 }
 
-static inline int clear_extent_buffer_uptodate(struct extent_io_tree *tree,
-				struct extent_buffer *eb)
+static inline int clear_extent_buffer_uptodate(struct extent_buffer *eb)
 {
 	eb->flags &= ~EXTENT_UPTODATE;
 	return 0;
@@ -147,10 +146,11 @@
 					 u64 bytenr, u32 blocksize);
 struct extent_buffer *find_first_extent_buffer(struct extent_io_tree *tree,
 					       u64 start);
-struct extent_buffer *alloc_extent_buffer(struct extent_io_tree *tree,
+struct extent_buffer *alloc_extent_buffer(struct btrfs_fs_info *fs_info,
 					  u64 bytenr, u32 blocksize);
 struct extent_buffer *btrfs_clone_extent_buffer(struct extent_buffer *src);
 void free_extent_buffer(struct extent_buffer *eb);
+void free_extent_buffer_nocache(struct extent_buffer *eb);
 int read_extent_from_disk(struct extent_buffer *eb,
 			  unsigned long offset, unsigned long len);
 int write_extent_to_disk(struct extent_buffer *eb);
diff --git a/include/btrfs/ioctl.h b/include/btrfs/ioctl.h
--- a/include/btrfs/ioctl.h
+++ b/include/btrfs/ioctl.h
@@ -25,11 +25,17 @@
 
 #include <asm/types.h>
 #include <linux/ioctl.h>
+#include <stddef.h>
 
 #ifndef __user
 #define __user
 #endif
 
+/* We don't want to include entire kerncompat.h */
+#ifndef BUILD_ASSERT
+#define BUILD_ASSERT(x)
+#endif
+
 #define BTRFS_IOCTL_MAGIC 0x94
 #define BTRFS_VOL_NAME_MAX 255
 
@@ -39,6 +45,7 @@
 	__s64 fd;
 	char name[BTRFS_PATH_NAME_MAX + 1];
 };
+BUILD_ASSERT(sizeof(struct btrfs_ioctl_vol_args) == 4096);
 
 #define BTRFS_DEVICE_PATH_NAME_MAX 1024
 
@@ -65,6 +72,7 @@
 	__u64	rsv_referenced;
 	__u64	rsv_exclusive;
 };
+BUILD_ASSERT(sizeof(struct btrfs_qgroup_limit) == 40);
 
 struct btrfs_qgroup_inherit {
 	__u64	flags;
@@ -74,11 +82,13 @@
 	struct btrfs_qgroup_limit lim;
 	__u64	qgroups[0];
 };
+BUILD_ASSERT(sizeof(struct btrfs_qgroup_inherit) == 72);
 
 struct btrfs_ioctl_qgroup_limit_args {
 	__u64	qgroupid;
 	struct btrfs_qgroup_limit lim;
 };
+BUILD_ASSERT(sizeof(struct btrfs_ioctl_qgroup_limit_args) == 48);
 
 #define BTRFS_SUBVOL_NAME_MAX 4039
 struct btrfs_ioctl_vol_args_v2 {
@@ -97,6 +107,7 @@
 		__u64 devid;
 	};
 };
+BUILD_ASSERT(sizeof(struct btrfs_ioctl_vol_args_v2) == 4096);
 
 /*
  * structure to report errors and progress to userspace, either as a
@@ -145,6 +156,7 @@
 	/* pad to 1k */
 	__u64 unused[(1024-32-sizeof(struct btrfs_scrub_progress))/8];
 };
+BUILD_ASSERT(sizeof(struct btrfs_ioctl_scrub_args) == 1024);
 
 #define BTRFS_IOCTL_DEV_REPLACE_CONT_READING_FROM_SRCDEV_MODE_ALWAYS	0
 #define BTRFS_IOCTL_DEV_REPLACE_CONT_READING_FROM_SRCDEV_MODE_AVOID	1
@@ -155,6 +167,7 @@
 	__u8 srcdev_name[BTRFS_DEVICE_PATH_NAME_MAX + 1];	/* in */
 	__u8 tgtdev_name[BTRFS_DEVICE_PATH_NAME_MAX + 1];	/* in */
 };
+BUILD_ASSERT(sizeof(struct btrfs_ioctl_dev_replace_start_params) == 2072);
 
 #define BTRFS_IOCTL_DEV_REPLACE_STATE_NEVER_STARTED	0
 #define BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED		1
@@ -169,6 +182,7 @@
 	__u64 num_write_errors;	/* out */
 	__u64 num_uncorrectable_read_errors;	/* out */
 };
+BUILD_ASSERT(sizeof(struct btrfs_ioctl_dev_replace_status_params) == 48);
 
 #define BTRFS_IOCTL_DEV_REPLACE_CMD_START			0
 #define BTRFS_IOCTL_DEV_REPLACE_CMD_STATUS			1
@@ -189,6 +203,7 @@
 
 	__u64 spare[64];
 };
+BUILD_ASSERT(sizeof(struct btrfs_ioctl_dev_replace_args) == 2600);
 
 struct btrfs_ioctl_dev_info_args {
 	__u64 devid;				/* in/out */
@@ -198,6 +213,7 @@
 	__u64 unused[379];			/* pad to 4k */
 	__u8 path[BTRFS_DEVICE_PATH_NAME_MAX];	/* out */
 };
+BUILD_ASSERT(sizeof(struct btrfs_ioctl_dev_info_args) == 4096);
 
 struct btrfs_ioctl_fs_info_args {
 	__u64 max_id;				/* out */
@@ -209,12 +225,14 @@
 	__u32 reserved32;
 	__u64 reserved[122];			/* pad to 1k */
 };
+BUILD_ASSERT(sizeof(struct btrfs_ioctl_fs_info_args) == 1024);
 
 struct btrfs_ioctl_feature_flags {
 	__u64 compat_flags;
 	__u64 compat_ro_flags;
 	__u64 incompat_flags;
 };
+BUILD_ASSERT(sizeof(struct btrfs_ioctl_feature_flags) == 24);
 
 /* balance control ioctl modes */
 #define BTRFS_BALANCE_CTL_PAUSE		1
@@ -292,6 +310,7 @@
 
 	__u64 unused[72];			/* pad to 1k */
 };
+BUILD_ASSERT(sizeof(struct btrfs_ioctl_balance_args) == 1024);
 
 #define BTRFS_INO_LOOKUP_PATH_MAX 4080
 struct btrfs_ioctl_ino_lookup_args {
@@ -299,6 +318,7 @@
 	__u64 objectid;
 	char name[BTRFS_INO_LOOKUP_PATH_MAX];
 };
+BUILD_ASSERT(sizeof(struct btrfs_ioctl_ino_lookup_args) == 4096);
 
 struct btrfs_ioctl_search_key {
 	/* which root are we searching.  0 is the tree of tree roots */
@@ -366,6 +386,7 @@
                                             *       to store item */
         __u64 buf[0];                      /* out - found items */
 };
+BUILD_ASSERT(sizeof(struct btrfs_ioctl_search_args_v2) == 112);
 
 /* With a @src_length of zero, the range from @src_offset->EOF is cloned! */
 struct btrfs_ioctl_clone_range_args {
@@ -373,6 +394,7 @@
 	__u64 src_offset, src_length;
 	__u64 dest_offset;
 };
+BUILD_ASSERT(sizeof(struct btrfs_ioctl_clone_range_args) == 32);
 
 /* flags for the defrag range ioctl */
 #define BTRFS_DEFRAG_RANGE_COMPRESS 1
@@ -402,6 +424,7 @@
 	__u32 reserved2;
 	struct btrfs_ioctl_same_extent_info info[0];
 };
+BUILD_ASSERT(sizeof(struct btrfs_ioctl_same_args) == 24);
 
 struct btrfs_ioctl_defrag_range_args {
 	/* start of the defrag operation */
@@ -433,6 +456,7 @@
 	/* spare for later */
 	__u32 unused[4];
 };
+BUILD_ASSERT(sizeof(struct btrfs_ioctl_defrag_range_args) == 48);
 
 struct btrfs_ioctl_space_info {
 	__u64 flags;
@@ -445,6 +469,7 @@
 	__u64 total_spaces;
 	struct btrfs_ioctl_space_info spaces[0];
 };
+BUILD_ASSERT(sizeof(struct btrfs_ioctl_space_args) == 16);
 
 struct btrfs_data_container {
 	__u32	bytes_left;	/* out -- bytes not needed to deliver output */
@@ -461,6 +486,7 @@
 	/* struct btrfs_data_container	*fspath;	   out */
 	__u64				fspath;		/* out */
 };
+BUILD_ASSERT(sizeof(struct btrfs_ioctl_ino_path_args) == 56);
 
 struct btrfs_ioctl_logical_ino_args {
 	__u64				logical;	/* in */
@@ -500,8 +526,9 @@
 	/* out values: */
 	__u64 values[BTRFS_DEV_STAT_VALUES_MAX];
 
-	__u64 unused[128 - 2 - BTRFS_DEV_STAT_VALUES_MAX]; /* pad to 1k */
+	__u64 unused[128 - 2 - BTRFS_DEV_STAT_VALUES_MAX]; /* pad to 1k + 8B */
 };
+BUILD_ASSERT(sizeof(struct btrfs_ioctl_get_dev_stats) == 1032);
 
 /* BTRFS_IOC_SNAP_CREATE is no longer used by the btrfs command */
 #define BTRFS_QUOTA_CTL_ENABLE	1
@@ -511,12 +538,14 @@
 	__u64 cmd;
 	__u64 status;
 };
+BUILD_ASSERT(sizeof(struct btrfs_ioctl_quota_ctl_args) == 16);
 
 struct btrfs_ioctl_quota_rescan_args {
 	__u64	flags;
 	__u64   progress;
 	__u64   reserved[6];
 };
+BUILD_ASSERT(sizeof(struct btrfs_ioctl_quota_rescan_args) == 64);
 
 struct btrfs_ioctl_qgroup_assign_args {
 	__u64 assign;
@@ -528,6 +557,8 @@
 	__u64 create;
 	__u64 qgroupid;
 };
+BUILD_ASSERT(sizeof(struct btrfs_ioctl_qgroup_create_args) == 16);
+
 struct btrfs_ioctl_timespec {
 	__u64 sec;
 	__u32 nsec;
@@ -542,8 +573,41 @@
 	__u64	flags;			/* in */
 	__u64	reserved[16];		/* in */
 };
+BUILD_ASSERT(sizeof(struct btrfs_ioctl_received_subvol_args) == 200);
 
 /*
+ * If we have a 32-bit userspace and 64-bit kernel, then the UAPI
+ * structures are incorrect, as the timespec structure from userspace
+ * is 4 bytes too small. We define these alternatives here for backward
+ * compatibility, the kernel understands both values.
+ */
+
+/*
+ * Structure size is different on 32bit and 64bit, has some padding if the
+ * structure is embedded. Packing makes sure the size is same on both, but will
+ * be misaligned on 64bit.
+ *
+ * NOTE: do not use in your code, this is for testing only
+ */
+struct btrfs_ioctl_timespec_32 {
+	__u64 sec;
+	__u32 nsec;
+} __attribute__ ((__packed__));
+
+struct btrfs_ioctl_received_subvol_args_32 {
+	char	uuid[BTRFS_UUID_SIZE];	/* in */
+	__u64	stransid;		/* in */
+	__u64	rtransid;		/* out */
+	struct btrfs_ioctl_timespec_32 stime; /* in */
+	struct btrfs_ioctl_timespec_32 rtime; /* out */
+	__u64	flags;			/* in */
+	__u64	reserved[16];		/* in */
+} __attribute__ ((__packed__));
+BUILD_ASSERT(sizeof(struct btrfs_ioctl_received_subvol_args_32) == 192);
+
+#define BTRFS_IOC_SET_RECEIVED_SUBVOL_32_COMPAT_DEFINED 1
+
+/*
  * Caller doesn't want file data in the send stream, even if the
  * search of clone sources doesn't find an extent. UPDATE_EXTENT
  * commands will be sent instead of WRITE commands.
@@ -576,7 +640,38 @@
 	__u64 flags;			/* in */
 	__u64 reserved[4];		/* in */
 };
+/*
+ * Size of structure depends on pointer width, was not caught in the early
+ * days.  Kernel handles pointer width differences transparently.
+ */
+BUILD_ASSERT(sizeof(__u64 *) == 8
+	     ? sizeof(struct btrfs_ioctl_send_args) == 72
+	     : (sizeof(void *) == 4
+		? sizeof(struct btrfs_ioctl_send_args) == 68
+		: 0));
 
+/*
+ * Different pointer width leads to structure size change. Kernel should accept
+ * both ioctl values (derived from the structures) for backward compatibility.
+ * Size of this structure is same on 32bit and 64bit though.
+ *
+ * NOTE: do not use in your code, this is for testing only
+ */
+struct btrfs_ioctl_send_args_64 {
+	__s64 send_fd;			/* in */
+	__u64 clone_sources_count;	/* in */
+	union {
+		__u64 __user *clone_sources;	/* in */
+		__u64 __clone_sources_alignment;
+	};
+	__u64 parent_root;		/* in */
+	__u64 flags;			/* in */
+	__u64 reserved[4];		/* in */
+} __attribute__((packed));
+BUILD_ASSERT(sizeof(struct btrfs_ioctl_send_args_64) == 72);
+
+#define BTRFS_IOC_SEND_64_COMPAT_DEFINED 1
+
 /* Error codes as returned by the kernel */
 enum btrfs_err_code {
 	notused,
@@ -688,6 +783,17 @@
 					struct btrfs_ioctl_logical_ino_args)
 #define BTRFS_IOC_SET_RECEIVED_SUBVOL _IOWR(BTRFS_IOCTL_MAGIC, 37, \
 				struct btrfs_ioctl_received_subvol_args)
+
+#ifdef BTRFS_IOC_SET_RECEIVED_SUBVOL_32_COMPAT_DEFINED
+#define BTRFS_IOC_SET_RECEIVED_SUBVOL_32 _IOWR(BTRFS_IOCTL_MAGIC, 37, \
+				struct btrfs_ioctl_received_subvol_args_32)
+#endif
+
+#ifdef BTRFS_IOC_SEND_64_COMPAT_DEFINED
+#define BTRFS_IOC_SEND_64 _IOW(BTRFS_IOCTL_MAGIC, 38, \
+		struct btrfs_ioctl_send_args_64)
+#endif
+
 #define BTRFS_IOC_SEND _IOW(BTRFS_IOCTL_MAGIC, 38, struct btrfs_ioctl_send_args)
 #define BTRFS_IOC_DEVICES_READY _IOR(BTRFS_IOCTL_MAGIC, 39, \
 				     struct btrfs_ioctl_vol_args)
diff --git a/include/btrfs/kerncompat.h b/include/btrfs/kerncompat.h
--- a/include/btrfs/kerncompat.h
+++ b/include/btrfs/kerncompat.h
@@ -68,6 +68,14 @@
 #define ULONG_MAX       (~0UL)
 #endif
 
+#define __token_glue(a,b,c)	___token_glue(a,b,c)
+#define ___token_glue(a,b,c)	a ## b ## c
+#ifdef DEBUG_BUILD_CHECKS
+#define BUILD_ASSERT(x)		extern int __token_glue(compile_time_assert_,__LINE__,__COUNTER__)[1-2*!(x)] __attribute__((unused))
+#else
+#define BUILD_ASSERT(x)
+#endif
+
 #ifndef BTRFS_DISABLE_BACKTRACE
 #define MAX_BACKTRACE	16
 static inline void print_trace(void)
@@ -78,26 +86,35 @@
 	size = backtrace(array, MAX_BACKTRACE);
 	backtrace_symbols_fd(array, size, 2);
 }
+#endif
 
-static inline void assert_trace(const char *assertion, const char *filename,
-			      const char *func, unsigned line, int val)
+static inline void warning_trace(const char *assertion, const char *filename,
+			      const char *func, unsigned line, long val)
 {
-	if (val)
+	if (!val)
 		return;
-	if (assertion)
-		fprintf(stderr, "%s:%d: %s: Assertion `%s` failed.\n",
-			filename, line, func, assertion);
-	else
-		fprintf(stderr, "%s:%d: %s: Assertion failed.\n", filename,
-			line, func);
+	fprintf(stderr,
+		"%s:%d: %s: Warning: assertion `%s` failed, value %ld\n",
+		filename, line, func, assertion, val);
+#ifndef BTRFS_DISABLE_BACKTRACE
 	print_trace();
-	exit(1);
+#endif
 }
 
-#define BUG() assert_trace(NULL, __FILE__, __func__, __LINE__, 0)
-#else
-#define BUG() assert(0)
+static inline void bugon_trace(const char *assertion, const char *filename,
+			      const char *func, unsigned line, long val)
+{
+	if (!val)
+		return;
+	fprintf(stderr,
+		"%s:%d: %s: BUG_ON `%s` triggered, value %ld\n",
+		filename, line, func, assertion, val);
+#ifndef BTRFS_DISABLE_BACKTRACE
+	print_trace();
 #endif
+	abort();
+	exit(1);
+}
 
 #ifdef __CHECKER__
 #define __force    __attribute__((force))
@@ -236,11 +253,16 @@
 	return (long) ptr;
 }
 
-static inline long IS_ERR(const void *ptr)
+static inline int IS_ERR(const void *ptr)
 {
 	return IS_ERR_VALUE((unsigned long)ptr);
 }
 
+static inline int IS_ERR_OR_NULL(const void *ptr)
+{
+	return !ptr || IS_ERR(ptr);
+}
+
 /*
  * This looks more complex than it should be. But we need to
  * get the type for the ~ right in round_down (it needs to be
@@ -269,27 +291,39 @@
 #define vfree(x) free(x)
 
 #ifndef BTRFS_DISABLE_BACKTRACE
-#define BUG_ON(c) assert_trace(#c, __FILE__, __func__, __LINE__, !(c))
-#else
-#define BUG_ON(c) assert(!(c))
-#endif
-
-#define WARN_ON(c) BUG_ON(c)
-
+static inline void assert_trace(const char *assertion, const char *filename,
+			      const char *func, unsigned line, long val)
+{
+	if (val)
+		return;
+	fprintf(stderr,
+		"%s:%d: %s: Assertion `%s` failed, value %ld\n",
+		filename, line, func, assertion, val);
 #ifndef BTRFS_DISABLE_BACKTRACE
-#define	ASSERT(c) assert_trace(#c, __FILE__, __func__, __LINE__, (c))
+	print_trace();
+#endif
+	abort();
+	exit(1);
+}
+#define	ASSERT(c) assert_trace(#c, __FILE__, __func__, __LINE__, (long)(c))
 #else
 #define ASSERT(c) assert(c)
 #endif
 
+#define BUG_ON(c) bugon_trace(#c, __FILE__, __func__, __LINE__, (long)(c))
+#define BUG() BUG_ON(1)
+#define WARN_ON(c) warning_trace(#c, __FILE__, __func__, __LINE__, (long)(c))
+
 #define container_of(ptr, type, member) ({                      \
         const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
 	        (type *)( (char *)__mptr - offsetof(type,member) );})
+#ifndef __bitwise
 #ifdef __CHECKER__
 #define __bitwise __bitwise__
 #else
 #define __bitwise
-#endif
+#endif /* __CHECKER__ */
+#endif	/* __bitwise */
 
 /* Alignment check */
 #define IS_ALIGNED(x, a)                (((x) & ((typeof(x))(a) - 1)) == 0)
diff --git a/include/btrfs/sizes.h b/include/btrfs/sizes.h
new file mode 100644
--- /dev/null
+++ b/include/btrfs/sizes.h
@@ -0,0 +1,47 @@
+/*
+ * include/linux/sizes.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef __LINUX_SIZES_H__
+#define __LINUX_SIZES_H__
+
+#define SZ_1				0x00000001
+#define SZ_2				0x00000002
+#define SZ_4				0x00000004
+#define SZ_8				0x00000008
+#define SZ_16				0x00000010
+#define SZ_32				0x00000020
+#define SZ_64				0x00000040
+#define SZ_128				0x00000080
+#define SZ_256				0x00000100
+#define SZ_512				0x00000200
+
+#define SZ_1K				0x00000400
+#define SZ_2K				0x00000800
+#define SZ_4K				0x00001000
+#define SZ_8K				0x00002000
+#define SZ_16K				0x00004000
+#define SZ_32K				0x00008000
+#define SZ_64K				0x00010000
+#define SZ_128K				0x00020000
+#define SZ_256K				0x00040000
+#define SZ_512K				0x00080000
+
+#define SZ_1M				0x00100000
+#define SZ_2M				0x00200000
+#define SZ_4M				0x00400000
+#define SZ_8M				0x00800000
+#define SZ_16M				0x01000000
+#define SZ_32M				0x02000000
+#define SZ_64M				0x04000000
+#define SZ_128M				0x08000000
+#define SZ_256M				0x10000000
+#define SZ_512M				0x20000000
+
+#define SZ_1G				0x40000000
+#define SZ_2G				0x80000000
+
+#endif /* __LINUX_SIZES_H__ */
diff --git a/include/sys/capability.h b/include/sys/capability.h
--- a/include/sys/capability.h
+++ b/include/sys/capability.h
@@ -27,7 +27,6 @@
 #define __user
 #endif
 #include <linux/capability.h>
-#include <linux/xattr.h>
 
 /*
  * POSIX capability types
