packages feed

btrfs (empty) → 0.1.0.0

raw patch · 19 files changed

+5786/−0 lines, 19 filesdep +basedep +btrfsdep +bytestringbuild-type:Customsetup-changed

Dependencies added: base, btrfs, bytestring, filepath, time, unix

Files

+ Data/Word/Endian.hs view
@@ -0,0 +1,62 @@+{-# LANGUAGE CPP #-}++module Data.Word.Endian where++import Data.Word (Word16, Word32, Word64)+import Data.Bits (rotateL, unsafeShiftL, unsafeShiftR, (.&.), (.|.))+import Foreign.Ptr (castPtr)+import Foreign.Storable (Storable(..))++#define MAKE_ENDIAN_WORD(native_type, endian_type, from, to, convert) \+newtype endian_type = endian_type {from :: native_type} deriving (Show, Eq); \+to :: native_type -> endian_type; \+to = endian_type; \+instance Storable endian_type where { \+    sizeOf _ = sizeOf (undefined :: native_type); \+    {-# INLINE sizeOf #-}; \+    alignment _ = alignment (undefined :: native_type); \+    {-# INLINE alignment #-}; \+    peek ptr = do {x <- peek (castPtr ptr); return (endian_type (convert x))}; \+    {-# INLINE peek #-}; \+    poke ptr (endian_type x) = poke (castPtr ptr) (convert x); \+    {-# INLINE poke #-}; \+}++#include "MachDeps.h"++#ifdef WORDS_BIGENDIAN+MAKE_ENDIAN_WORD(Word16, LE16, fromLE16, toLE16, invert16)+MAKE_ENDIAN_WORD(Word32, LE32, fromLE32, toLE32, invert32)+MAKE_ENDIAN_WORD(Word64, LE64, fromLE64, toLE64, invert64)+MAKE_ENDIAN_WORD(Word16, BE16, fromBE16, toBE16, id)+MAKE_ENDIAN_WORD(Word32, BE32, fromBE32, toBE32, id)+MAKE_ENDIAN_WORD(Word64, BE64, fromBE64, toBE64, id)+#else+MAKE_ENDIAN_WORD(Word16, LE16, fromLE16, toLE16, id)+MAKE_ENDIAN_WORD(Word32, LE32, fromLE32, toLE32, id)+MAKE_ENDIAN_WORD(Word64, LE64, fromLE64, toLE64, id)+MAKE_ENDIAN_WORD(Word16, BE16, fromBE16, toBE16, invert16)+MAKE_ENDIAN_WORD(Word32, BE32, fromBE32, toBE32, invert32)+MAKE_ENDIAN_WORD(Word64, BE64, fromBE64, toBE64, invert64)+#endif++invert16 :: Word16 -> Word16+invert16 x = x `rotateL` 8++invert32 :: Word32 -> Word32+invert32 x =+    ((x               ) `unsafeShiftR` 24) .|.+    ((x .&. 0x00ff0000) `unsafeShiftR`  8) .|.+    ((x .&. 0x0000ff00) `unsafeShiftL`  8) .|.+    ((x               ) `unsafeShiftL` 24)++invert64 :: Word64 -> Word64+invert64 x =+    ((x                       ) `unsafeShiftR` 56) .|.+    ((x .&. 0x00ff000000000000) `unsafeShiftR` 40) .|.+    ((x .&. 0x0000ff0000000000) `unsafeShiftR` 24) .|.+    ((x .&. 0x000000ff00000000) `unsafeShiftR`  8) .|.+    ((x .&. 0x00000000ff000000) `unsafeShiftL`  8) .|.+    ((x .&. 0x0000000000ff0000) `unsafeShiftL` 24) .|.+    ((x .&. 0x000000000000ff00) `unsafeShiftL` 40) .|.+    ((x                       ) `unsafeShiftL` 56)
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c) 2014, Marios Titas++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++    * Redistributions of source code must retain the above copyright+      notice, this list of conditions and the following disclaimer.++    * Redistributions in binary form must reproduce the above+      copyright notice, this list of conditions and the following+      disclaimer in the documentation and/or other materials provided+      with the distribution.++    * Neither the name of Marios Titas nor the names of other+      contributors may be used to endorse or promote products derived+      from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ Setup.hs view
@@ -0,0 +1,40 @@+import Distribution.Simple+import Distribution.Simple.Setup+import Distribution.Simple.Utils+import Distribution.Simple.BuildPaths+import Distribution.Simple.LocalBuildInfo+import Distribution.PackageDescription+import Distribution.ModuleName (fromString)+import System.IO+import System.FilePath++main :: IO ()+main = defaultMainWithHooks simpleUserHooks+    { confHook = customConf+    , buildHook = customBuild+    }++customConf gh cFlags = do+    lbi <- confHook simpleUserHooks gh cFlags+    -- modify the package description to add the auto-generated module+    let desc = localPkgDescr lbi+        Just lib = library desc+        modName = fromString "System.Linux.Btrfs.ByteString"+        lib' = lib {exposedModules = exposedModules lib ++ [modName]}+        desc' = desc {library = Just lib'}+    return lbi {localPkgDescr = desc'}++customBuild desc lbi hooks bFlags = do+    let verbosity = fromFlag (buildVerbosity bFlags)++    -- create System/Linux/Btrfs/ByteString.hsc+    let dir = autogenModulesDir lbi </> "System/Linux/Btrfs"+    createDirectoryIfMissingVerbose verbosity True dir+    withFile (dir </> "ByteString.hsc") WriteMode $ \oHdl -> do+        hPutStrLn oHdl "#define BTRFS_RAW_PATHS 1"+        withFile "System/Linux/Btrfs.hsc" ReadMode $ \iHdl -> do+            _ <- hGetLine iHdl -- skip the first line+            contents <- hGetContents iHdl+            hPutStr oHdl contents++    buildHook simpleUserHooks desc lbi hooks bFlags
+ System/Linux/Btrfs.hsc view
@@ -0,0 +1,1058 @@+#define BTRFS_RAW_PATHS 0+{- |+Module      : System.Linux.Btrfs++Stability   : provisional+Portability : non-portable (requires Linux)++Most functions in this module come in two flavors: one that operates on+file descriptors and another one that operates on file paths. The former+can be distinguished by the @Fd@ suffix in their names.+-}++{-# LANGUAGE CPP #-}++#if BTRFS_RAW_PATHS+##define FILEPATH RawFilePath+module System.Linux.Btrfs.ByteString+#else+##define FILEPATH FilePath+module System.Linux.Btrfs+#endif+    (+    -- * Basic types+      FileSize, ObjectType, ObjectId, InodeNum, SubvolId+    -- * File cloning+    , cloneFd, clone, cloneNew+    , cloneRangeFd, cloneRange+    , CloneResult(..)+    , cloneRangeIfSameFd, cloneRangeIfSame+    -- * Subvolumes and snapshots+    , createSubvol+    , destroySubvol+    , snapshotFd, snapshot+    , getSubvolReadOnlyFd, getSubvolReadOnly+    , setSubvolReadOnlyFd, setSubvolReadOnly+    , getSubvolFd, getSubvol+    , lookupSubvolFd, lookupSubvol+    , resolveSubvolFd, resolveSubvol+    , rootSubvol+    , listSubvolsFd, listSubvols+    , listSubvolPathsFd, listSubvolPaths+    , childSubvolsFd, childSubvols+    , childSubvolPathsFd, childSubvolPaths+    , SubvolInfo(..)+    , getSubvolInfoFd, getSubvolInfo+    , getSubvolByUuidFd, getSubvolByUuid+    , getSubvolByReceivedUuidFd, getSubvolByReceivedUuid+    -- * Defragging+    , defragFd, defrag+    -- * Sync+    , syncFd, sync+    , startSyncFd, startSync+    , waitSyncFd, waitSync+    -- * Inspect internal+    , resolveLogicalFd, resolveLogical+    , resolveInodeFd, resolveInode+    , lookupInodeFd, lookupInode+    -- * Miscellaneous+    , getFileNoCOWFd, getFileNoCOW+    , setFileNoCOWFd, setFileNoCOW+    -- * Tree search+    -- | Low-level API for tree search using the @BTRFS_IOC_TREE_SEARCH@+    -- @ioctl@.+    , SearchKey(..)+    , defaultSearchKey+    , SearchHeader(..)+    , treeSearchFd, treeSearch+    , treeSearchListFd, treeSearchList+    , findFirstItemFd, findFirstItem+    ) where++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+import Data.IORef+import Data.Time.Clock (UTCTime)+import Data.Monoid+import System.Linux.Btrfs.FilePathLike++import Foreign+import Foreign.C.Types+import Foreign.C.String (CStringLen)+import Foreign.C.Error++import Data.Word.Endian+import System.Linux.Btrfs.Time+import System.Linux.Btrfs.UUID++#include <linux/btrfs.h>+#define __IOCTL_+#include <btrfs/ctree.h>++#include <linux/fs.h>++foreign import ccall safe+    ioctl :: Fd -> CULong -> Ptr a -> IO CInt+foreign import ccall unsafe "ioctl"+    ioctl_fast :: Fd -> CULong -> Ptr a -> IO CInt++type FileSize = Word64++type ObjectType = Word8++type ObjectId = Word64++type InodeNum = ObjectId++type SubvolId = ObjectId++--------------------------------------------------------------------------------++cloneFd :: Fd -> Fd -> IO ()+cloneFd srcFd dstFd =+    throwErrnoIfMinus1_ "cloneFd" $+        ioctl_fast dstFd (#const BTRFS_IOC_CLONE) srcFdP+  where+    srcFdP = intPtrToPtr (fromIntegral srcFd)++-- | Clone an entire file to an existing file.+--+-- Note: calls the @BTRFS_IOC_CLONE@ @ioctl@.+clone+    :: FILEPATH -- ^ The source file.+    -> FILEPATH -- ^ The destination file.+    -> IO ()+clone srcPath dstPath =+    withFd srcPath ReadOnly $ \srcFd ->+    withFd dstPath WriteOnly $ \dstFd ->+        cloneFd srcFd dstFd++-- | Like 'clone' except that it will create or truncate the destination+-- file if necessary. This is similar to @cp --reflink=always@.+--+-- Note: calls the @BTRFS_IOC_CLONE@ @ioctl@.+cloneNew :: FILEPATH -> FILEPATH -> IO ()+cloneNew srcPath dstPath =+    withFd srcPath ReadOnly $ \srcFd -> do+        stat <- getFdStatus srcFd+        let mode = fileMode stat+        bracket (openFd dstPath WriteOnly (Just mode) defaultFileFlags {trunc = True}) closeFd $ \dstFd ->+            cloneFd srcFd dstFd++cloneRangeFd :: Fd -> FileSize -> FileSize -> Fd -> FileSize -> IO ()+cloneRangeFd srcFd srcOff srcLen dstFd dstOff =+    allocaBytesZero (#size struct btrfs_ioctl_clone_range_args) $ \cra -> do+        (#poke struct btrfs_ioctl_clone_range_args, src_fd     ) cra (fromIntegral srcFd :: Int64)+        (#poke struct btrfs_ioctl_clone_range_args, src_offset ) cra (srcOff :: Word64)+        (#poke struct btrfs_ioctl_clone_range_args, src_length ) cra (srcLen :: Word64)+        (#poke struct btrfs_ioctl_clone_range_args, dest_offset) cra (dstOff :: Word64)+        throwErrnoIfMinus1_ "cloneRangeFd" $+            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.+--+-- Note: calls the @BTRFS_IOC_CLONE_RANGE@ @ioctl@.+cloneRange+    :: FILEPATH -- ^ The source file.+    -> FileSize -- ^ The offset within the source file.+    -> FileSize -- ^ The length of the range. A length of 0 selects the range+                -- from the source offset to the end.+    -> FILEPATH -- ^ The destination file.+    -> FileSize -- ^ The offset within the destination file.+    -> IO ()+cloneRange srcPath srcOff srcLen dstPath dstOff =+    withFd srcPath ReadOnly $ \srcFd ->+    withFd dstPath WriteOnly $ \dstFd ->+        cloneRangeFd srcFd srcOff srcLen dstFd dstOff++#ifdef BTRFS_IOC_FILE_EXTENT_SAME+data SameExtentInfoIn = SameExtentInfoIn+    Fd       -- file descriptor (stored as Int64)+    FileSize -- offset++instance Storable SameExtentInfoIn where+    sizeOf _ = (#size struct btrfs_ioctl_same_extent_info)+    alignment _ = alignment (undefined :: CInt)+    poke ptr (SameExtentInfoIn dstFd dstOff) = do+        memset ptr 0 (#size struct btrfs_ioctl_same_extent_info)+        let dstFd' = fromIntegral dstFd :: Int64+        (#poke struct btrfs_ioctl_same_extent_info, fd) ptr dstFd'+        (#poke struct btrfs_ioctl_same_extent_info, logical_offset) ptr dstOff+    peek _ = error "not implemented"++data SameExtentInfoOut = SameExtentInfoOut+    Int32    -- status+    FileSize -- bytes deduped++instance Storable SameExtentInfoOut where+    sizeOf _ = (#size struct btrfs_ioctl_same_extent_info)+    alignment _ = alignment (undefined :: CInt)+    poke _ _ = error "not implemented"+    peek ptr = do+        status <- (#peek struct btrfs_ioctl_same_extent_info, status       ) ptr+        bytes  <- (#peek struct btrfs_ioctl_same_extent_info, bytes_deduped) ptr+        return (SameExtentInfoOut status bytes)+#endif++-- | The result of a 'cloneRangeIfSame' operation.+data CloneResult+    = CRError IOError    -- ^ Cloning failed because of an error.+    | CRDataDiffers      -- ^ No cloning was performed because the contents+                         -- of the source and the destination file differ.+    | CRSuccess FileSize -- ^ Cloning succeeded, the returned integer+                         -- indicates the number of bytes that were+                         -- deduped.+    deriving (Show, Eq)++cloneRangeIfSameFd :: Fd -> FileSize -> FileSize -> [(Fd, FileSize)] -> IO [CloneResult]+#ifndef BTRFS_IOC_FILE_EXTENT_SAME+cloneRangeIfSameFd _ _ _ _ =+    error "System.Linux.Btrfs.cloneRangeIfSameFd: not supported"+#else+cloneRangeIfSameFd srcFd srcOff srcLen dsts = do+    unless (dstCount <= maxCount) $+        ioError $ flip ioeSetErrorString ("too many destination files (more than " +++                                          show maxCount ++ ")")+                $ mkIOError illegalOperationErrorType "cloneRangeIfSameFd" Nothing Nothing+    allocaBytes saSize $ \sa -> do+        memset sa 0 (#size struct btrfs_ioctl_same_args)+        (#poke struct btrfs_ioctl_same_args, logical_offset) sa srcOff+        (#poke struct btrfs_ioctl_same_args, length        ) sa srcLen+        (#poke struct btrfs_ioctl_same_args, dest_count    ) sa dstCount'+        let info = (#ptr struct btrfs_ioctl_same_args, info) sa+        pokeArray info (map (uncurry SameExtentInfoIn) dsts)+        throwErrnoIfMinus1_ "cloneRangeIfSameFd" $+            ioctl srcFd (#const BTRFS_IOC_FILE_EXTENT_SAME) sa+        res <- peekArray dstCount info+        return $ flip map res $ \(SameExtentInfoOut status bytes) ->+            if status == 0 then+                CRSuccess bytes+            else if status == (#const BTRFS_SAME_DATA_DIFFERS) then+                CRDataDiffers+            else if status <= 0 then+                CRError $ errnoToIOError "cloneRangeIfSameFd"+                                         (Errno $ fromIntegral $ -status)+                                         Nothing Nothing+            else+                error $ "unknown status value (" ++ show status ++ ")"+  where+    saSize = (#size struct btrfs_ioctl_same_args) ++             dstCount * (#size struct btrfs_ioctl_same_extent_info)+    dstCount = length dsts+    dstCount' = fromIntegral dstCount :: Word64+    maxCount = fromIntegral (maxBound :: Word16)+#endif++-- | Similar to 'cloneRange' except that it performs the cloning only if+-- the data ranges contain identical data.+-- Additionally, it accepts multiple destination files. The same thing can+-- be accomplished with 'cloneRange' in conjunction with file locking but+-- this function uses in-kernel locking to guarantee that the deduplicated+-- data is identical at the time of the operation. On the other hand, this+-- function will not clone arbitrarily large ranges; the kernel has an upper+-- limit for the length and if cloning bigger ranges is desired then it+-- has to be called multiple times. Note that cloning may succeed for some+-- of the destination files and fail for others. Because of that, this+-- function returns a list of outcomes, one for each destination file, and+-- no exceptions will be raised for the failed files.+--+-- Note: calls the @BTRFS_IOC_FILE_EXTENT_SAME@ @ioctl@.+--+-- /Requires Linux 3.12 or later./+cloneRangeIfSame+    :: FILEPATH               -- ^ The source file.+    -> FileSize               -- ^ The offset within the source file.+    -> FileSize               -- ^ The length of the range.+    -> [(FILEPATH, FileSize)] -- ^ The destination files and corresponding offsets.+    -> IO [CloneResult]+cloneRangeIfSame srcPath srcOff srcLen dstsP0 =+    withFd srcPath ReadOnly $ \srcFd ->+        loop srcFd (reverse dstsP0) []+  where+    loop srcFd ((dstPath, dstOff) : dstsP) dsts =+        withFd dstPath WriteOnly $ \fd ->+            loop srcFd dstsP ((fd, dstOff) : dsts)+    loop srcFd [] dsts =+        cloneRangeIfSameFd srcFd srcOff srcLen dsts++--------------------------------------------------------------------------------++simpleSubvolOp :: String -> FILEPATH -> CULong -> IO ()+simpleSubvolOp loc path req =+    withSplitPathOpenParent loc (#const BTRFS_PATH_NAME_MAX) path $ \(cName, l) dirFd ->+        allocaBytesZero (#size struct btrfs_ioctl_vol_args) $ \iva -> do+            let ivaName = (#ptr struct btrfs_ioctl_vol_args, name) iva+            copyBytes ivaName cName l+            throwErrnoIfMinus1_ loc $+                ioctl dirFd req iva++-- | Create an (initially) empty new subvolume.+--+-- Note: calls the @BTRFS_IOC_SUBVOL_CREATE@ @ioctl@.+createSubvol :: FILEPATH -> IO ()+createSubvol path =+    simpleSubvolOp "createSubvol" path (#const BTRFS_IOC_SUBVOL_CREATE)++-- | Destroy (delete) a subvolume.+--+-- Note: calls the @BTRFS_IOC_SNAP_DESTROY@ @ioctl@.+destroySubvol :: FILEPATH -> IO ()+destroySubvol path =+    simpleSubvolOp "destroySubvol" path (#const BTRFS_IOC_SNAP_DESTROY)++snapshotFd :: Fd -> FILEPATH -> Bool -> IO ()+snapshotFd srcFd dstPath readOnly =+    withSplitPathOpenParent "snapshotFd" (#const BTRFS_SUBVOL_NAME_MAX) dstPath $ \(cName, l) dirFd ->+        allocaBytesZero (#size struct btrfs_ioctl_vol_args_v2) $ \iva -> do+            let ivaName = (#ptr struct btrfs_ioctl_vol_args_v2, name) iva+            copyBytes ivaName cName l+            (#poke struct btrfs_ioctl_vol_args_v2, fd) iva (fromIntegral srcFd :: Int64)+            when readOnly $+                setFlags ((#ptr struct btrfs_ioctl_vol_args_v2, flags) iva)+                    ((#const BTRFS_SUBVOL_RDONLY) :: Word64)+            throwErrnoIfMinus1_ "snapshotFd" $+                ioctl dirFd (#const BTRFS_IOC_SNAP_CREATE_V2) iva++-- | Create a snapshot of an existing subvolume.+--+-- Note: calls the @BTRFS_IOC_SNAP_CREATE_V2@ @ioctl@.+snapshot+    :: FILEPATH -- ^ The source subvolume.+    -> FILEPATH -- ^ The destination subvolume (must not exist).+    -> Bool     -- ^ Make the subvolume read-only?+    -> IO ()+snapshot srcPath dstPath readOnly =+    withFd srcPath ReadOnly $ \srcFd ->+        snapshotFd srcFd dstPath readOnly++getSubvolReadOnlyFd :: Fd -> IO Bool+getSubvolReadOnlyFd fd =+    alloca $ \flagsPtr -> do+        throwErrnoIfMinus1_ "getSubvolReadOnlyFd" $+            ioctl fd (#const BTRFS_IOC_SUBVOL_GETFLAGS) flagsPtr+        flags <- peek flagsPtr :: IO Word64+        return (flags .&. (#const BTRFS_SUBVOL_RDONLY) /= 0)++-- | Is the subvolume read-only?+--+-- Note: calls the @BTRFS_IOC_SUBVOL_GETFLAGS@ @ioctl@.+getSubvolReadOnly :: FILEPATH -> IO Bool+getSubvolReadOnly path = withFd path ReadOnly getSubvolReadOnlyFd++setSubvolReadOnlyFd :: Fd -> Bool -> IO ()+setSubvolReadOnlyFd fd readOnly =+    alloca $ \flagsPtr -> do+        throwErrnoIfMinus1_ "setSubvolReadOnlyFd" $+            ioctl fd (#const BTRFS_IOC_SUBVOL_GETFLAGS) flagsPtr+        if readOnly then+            setFlags flagsPtr ((#const BTRFS_SUBVOL_RDONLY) :: Word64)+        else+            clearFlags flagsPtr ((#const BTRFS_SUBVOL_RDONLY) :: Word64)+        throwErrnoIfMinus1_ "setSubvolReadOnlyFd" $+            ioctl fd (#const BTRFS_IOC_SUBVOL_SETFLAGS) flagsPtr++-- | Make a subvolume read-only (or read-write).+--+-- Note: calls the @BTRFS_IOC_SUBVOL_GETFLAGS@ and+-- @BTRFS_IOC_SUBVOL_SETFLAGS@ @ioctl@s.+setSubvolReadOnly :: FILEPATH -> Bool -> IO ()+setSubvolReadOnly path readOnly =+    withFd path ReadOnly $ \fd -> setSubvolReadOnlyFd fd readOnly++getSubvolFd :: Fd -> IO SubvolId+getSubvolFd fd = do+    (subvolId, _) <- lookupInodeFd fd 0 (#const BTRFS_FIRST_FREE_OBJECTID)+    return subvolId++-- | Find the id of the subvolume where the given file resides. This is+-- merely a wrapper around 'lookupInode' provided for convenience.+getSubvol :: FILEPATH -> IO SubvolId+getSubvol path = withFd path ReadOnly getSubvolFd++lookupSubvolFd :: Fd -> SubvolId -> IO (SubvolId, InodeNum, FILEPATH)+lookupSubvolFd fd subvolId = do+    let sk = defaultSearchKey+            { skTreeId      = (#const BTRFS_ROOT_TREE_OBJECTID)+            , skMinObjectId = subvolId+            , skMaxObjectId = subvolId+            , skMinType     = (#const BTRFS_ROOT_BACKREF_KEY)+            , skMaxType     = (#const BTRFS_ROOT_BACKREF_KEY)+            }+    findFirstItemFd fd sk $ \sh rr -> do+        (dirId, name) <- peekRootRef rr+        return (shOffset sh, dirId, name)++-- | Given the id of a subvolume, find the id of the parent subvolume, the+-- inode number of the directory containing it, and its name. This is+-- a wrapper around 'treeSearch'.+lookupSubvol+    :: FILEPATH -- ^ The mount point of the volume (or any file in that volume).+    -> SubvolId -- ^ The id of the subvolume.+    -> IO (SubvolId, InodeNum, FILEPATH)+lookupSubvol path subvolId =+    withFd path ReadOnly $ \fd ->+        lookupSubvolFd fd subvolId++resolveSubvolFd :: Fd -> SubvolId -> IO FILEPATH+resolveSubvolFd fd subvolId+    | subvolId == rootSubvol = return mempty+    | otherwise = do+        (parentId, dirId, name) <- lookupSubvolFd fd subvolId+        parentPath <- resolveSubvolFd fd parentId+        if dirId == (#const BTRFS_FIRST_FREE_OBJECTID) then+            return (parentPath </> name)+        else do+            (_, dirName) <- lookupInodeFd fd parentId dirId+            return (parentPath </> dirName </> name)++-- | Given the id of a subvolume, find its path relative to the root of the+-- volume. This function calls 'lookupSubvol' recursively.+resolveSubvol+    :: FILEPATH -- ^ The mount point of the volume (or any file in that volume).+    -> SubvolId -- ^ The id of the subvolume.+    -> IO FILEPATH+resolveSubvol path subvolId =+    withFd path ReadOnly $ \fd ->+        resolveSubvolFd fd subvolId++-- | The id the root subvolume.+rootSubvol :: SubvolId+rootSubvol = (#const BTRFS_FS_TREE_OBJECTID)++listSubvolsFd :: Fd -> IO [(SubvolId, SubvolId, InodeNum, FILEPATH)]+listSubvolsFd fd = do+    let sk = defaultSearchKey+            { skTreeId      = (#const BTRFS_ROOT_TREE_OBJECTID)+            , skMinObjectId = (#const BTRFS_FIRST_FREE_OBJECTID)+            , skMaxObjectId = (#const BTRFS_LAST_FREE_OBJECTID)+            , skMinType     = (#const BTRFS_ROOT_BACKREF_KEY)+            , skMaxType     = (#const BTRFS_ROOT_BACKREF_KEY)+            }+    treeSearchListFd fd sk unpack+  where+    unpack sh rr+        | shType sh /= (#const BTRFS_ROOT_BACKREF_KEY) =+            return Nothing+        | otherwise = do+            (dirId, name) <- peekRootRef rr+            return $ Just (shObjectId sh, shOffset sh, dirId, name)++-- | Find all subvolumes of the given volume. For each subvolume found, it+-- returns: its id, the id of its parent subvolume, the inode number of the+-- directory containing it, and its name. This is a wrapper around+-- 'treeSearch'.+listSubvols :: FILEPATH -> IO [(SubvolId, SubvolId, InodeNum, FILEPATH)]+listSubvols path =+    withFd path ReadOnly listSubvolsFd++listSubvolPathsFd :: Fd -> IO [(SubvolId, SubvolId, FILEPATH)]+listSubvolPathsFd fd = do+    subvols <- listSubvolsFd fd+    forM subvols $ \(subvolId, parentId, _, _) -> do+        path <- resolveSubvolFd fd subvolId+        return (subvolId, parentId, path)++-- | Find all subvolumes of the given volume. For each subvolume found, it+-- returns: its id, the id of its parent subvolume, and its path relative+-- to the root of the volume. This is a wrapper around 'treeSearch' and+-- 'resolveSubvol'.+listSubvolPaths :: FILEPATH -> IO [(SubvolId, SubvolId, FILEPATH)]+listSubvolPaths path =+    withFd path ReadOnly listSubvolPathsFd++childSubvolsFd :: Fd -> SubvolId -> IO [(SubvolId, InodeNum, FILEPATH)]+childSubvolsFd fd subvolId = do+    let sk = defaultSearchKey+            { skTreeId      = (#const BTRFS_ROOT_TREE_OBJECTID)+            , skMinObjectId = subvolId+            , skMaxObjectId = subvolId+            , skMinType     = (#const BTRFS_ROOT_REF_KEY)+            , skMaxType     = (#const BTRFS_ROOT_REF_KEY)+            }+    treeSearchListFd fd sk unpack+  where+    unpack sh rr+        | shType sh /= (#const BTRFS_ROOT_REF_KEY) =+            return Nothing+        | otherwise = do+            (dirId, name) <- peekRootRef rr+            return $ Just (shOffset sh, dirId, name)++-- | Find all child subvolumes of the given subvolume. For each child,+-- returns its id, the inode number of the directory containing it, and its+-- name. This is a wrapper around 'treeSearch'.+childSubvols+    :: FILEPATH -- ^ The mount point of the volume (or any file in that volume).+    -> SubvolId -- ^ The id of the subvolume.+    -> IO [(SubvolId, InodeNum, FILEPATH)]+childSubvols path subvolId =+    withFd path ReadOnly $ \fd ->+        childSubvolsFd fd subvolId++childSubvolPathsFd :: Fd -> SubvolId -> IO [(SubvolId, FILEPATH)]+childSubvolPathsFd fd subvolId = do+    childs <- childSubvolsFd fd subvolId+    forM childs $ \(childId, dirId, name) ->+        if dirId == (#const BTRFS_FIRST_FREE_OBJECTID) then+            return (childId, name)+        else do+            (_, dirName) <- lookupInodeFd fd subvolId dirId+            return (childId, dirName </> name)++-- | Find all child subvolumes of the given subvolume. For each child,+-- returns its id and its path relative to the root of the parent.+-- This is a wrapper around 'treeSearch' and 'lookupInode'.+childSubvolPaths+    :: FILEPATH -- ^ The mount point of the volume (or any file in that volume).+    -> SubvolId -- ^ The id of the subvolume.+    -> IO [(SubvolId, FILEPATH)]+childSubvolPaths path subvolId =+    withFd path ReadOnly $ \fd ->+        childSubvolPathsFd fd subvolId++-- | Information about a subvolume.+data SubvolInfo = SubvolInfo+    { siGeneration :: Word64+        -- ^ The generation when the subvolume was last modified.+    , siLastSnapshot :: Maybe Word64+        -- ^ The generation when the most recent snapshot of this subvolume was taken.+    , siParSnapGen :: Maybe Word64+        -- ^ The generation of the snapshot parent at the time when the snapshot+        -- was taken. Defined if only if this is a snapshot.+    , siReadOnly :: Bool+        -- ^ Is this a read-only subvolume?+    , siUuid :: Maybe UUID+        -- ^ The UUID of the subvolume.+    , siPUuid :: Maybe UUID+        -- ^ The UUID of the snapshot parent.+    , siReceivedUuid :: Maybe UUID+        -- ^ The UUID of the source subvolume that this subvolume was+        -- received from. This is always defined for received subvolumes.+    , siCTransId :: Maybe Word64+        -- ^ The generation when an inode was last modified.+    , siOTransId :: Maybe Word64+        -- ^ The generation when the subvolume was created.+    , siSTransId :: Maybe Word64+        -- ^ The generation of the source subvolume that this subvolume was+        -- received from. This is always defined for received subvolumes.+    , siRTransId :: Maybe Word64+        -- ^ The generation when the subvolume was received. This is always+        -- defined for received subvolumes.+    , siCTime :: Maybe UTCTime+        -- ^ The time when an inode was last modified.+    , siOTime :: Maybe UTCTime+        -- ^ The time when the subvolume was created.+    , siSTime :: Maybe UTCTime+        -- ^ The timestamp that corresponds to 'siSTransId'.+    , siRTime :: Maybe UTCTime+        -- ^ The time when the subvolume was received. This is always+        -- defined for received subvolumes.+    }+  deriving (Show, Eq)++getSubvolInfoFd :: Fd -> SubvolId -> IO SubvolInfo+getSubvolInfoFd fd subvolId+    | subvolId /= rootSubvol &&+        (subvolId < (#const BTRFS_FIRST_FREE_OBJECTID) || subvolId > (#const BTRFS_LAST_FREE_OBJECTID)) =+          ioError $ mkIOError doesNotExistErrorType+                              "getSubvolInfoFd"+                              Nothing Nothing+    | otherwise = do+        let sk = defaultSearchKey+                { skTreeId      = (#const BTRFS_ROOT_TREE_OBJECTID)+                , skMinObjectId = subvolId+                , skMaxObjectId = subvolId+                , skMinType     = (#const BTRFS_ROOT_ITEM_KEY)+                , skMaxType     = (#const BTRFS_ROOT_ITEM_KEY)+                }+        findFirstItemFd fd sk unpack+  where+    unpack sh ri = do+        LE64 generation <- (#peek struct btrfs_root_item, generation) ri+        LE64 lastSnapshot <- (#peek struct btrfs_root_item, last_snapshot) ri+        LE64 flags <- (#peek struct btrfs_root_item, flags) ri+        LE64 generationV2 <- (#peek struct btrfs_root_item, generation_v2) ri+        let nv2 = generationV2 < generation -- not version 2+        uuid <- (#peek struct btrfs_root_item, uuid) ri :: IO UUID+        pUuid <- (#peek struct btrfs_root_item, parent_uuid) ri :: IO UUID+        receivedUuid <- (#peek struct btrfs_root_item, received_uuid) ri :: IO UUID+        LE64 cTransId <- (#peek struct btrfs_root_item, ctransid) ri+        LE64 oTransId <- (#peek struct btrfs_root_item, otransid) ri+        LE64 sTransId <- (#peek struct btrfs_root_item, stransid) ri+        LE64 rTransId <- (#peek struct btrfs_root_item, rtransid) ri+        BtrfsTime cTime <- (#peek struct btrfs_root_item, ctime) ri+        BtrfsTime oTime <- (#peek struct btrfs_root_item, otime) ri+        BtrfsTime sTime <- (#peek struct btrfs_root_item, stime) ri+        BtrfsTime rTime <- (#peek struct btrfs_root_item, rtime) ri+        return $ SubvolInfo+            { siGeneration = generation+            , siLastSnapshot = nothingIf (lastSnapshot == 0) $ lastSnapshot+            , siParSnapGen = nothingIf (shOffset sh == 0) $ shOffset sh+            , siReadOnly = flags .&. (#const BTRFS_SUBVOL_RDONLY) /= 0+            , siUuid = nothingIf nv2 uuid+            , siPUuid = nothingIf (nv2 || shOffset sh == 0) pUuid+            , siReceivedUuid = nothingIf (nv2 || sTransId == 0) receivedUuid+            , siCTransId = nothingIf nv2 cTransId+            , siOTransId = nothingIf (nv2 || oTransId == 0) oTransId+            , siSTransId = nothingIf (nv2 || sTransId == 0) sTransId+            , siRTransId = nothingIf (nv2 || rTransId == 0) rTransId+            , siCTime = nothingIf nv2 cTime+            , siOTime = nothingIf (nv2 || oTransId == 0) oTime+            , siSTime = nothingIf (nv2 || sTransId == 0) sTime+            , siRTime = nothingIf (nv2 || rTransId == 0) rTime+            }++-- | Retrieve information about a subvolume.+getSubvolInfo+    :: FILEPATH -- ^ The mount point of the volume (or any file in that volume).+    -> SubvolId -- ^ The id of the subvolume.+    -> IO SubvolInfo+getSubvolInfo path subvolId =+    withFd path ReadOnly $ \fd ->+        getSubvolInfoFd fd subvolId++searchByUuidFd :: ObjectType -> Fd -> UUID -> IO SubvolId+searchByUuidFd typ fd (UUID hBE lBE) = do+    let sk = defaultSearchKey+            { skTreeId      = (#const BTRFS_UUID_TREE_OBJECTID)+            , skMinObjectId = hLE+            , skMaxObjectId = hLE+            , skMinType     = typ+            , skMaxType     = typ+            , skMinOffset   = lLE+            , skMaxOffset   = lLE+            }+    findFirstItemFd fd sk $ \_ ptr ->+        liftM fromLE64 $ peek ptr+  where+    -- UUID is stored as two big-endian integers+    -- but in the UUID tree, little-endian integers are used+    lLE = invert64 lBE+    hLE = invert64 hBE++getSubvolByUuidFd :: Fd -> UUID -> IO SubvolId+getSubvolByUuidFd =+    searchByUuidFd (#const BTRFS_UUID_KEY_SUBVOL)++-- | Find the id of a subvolume, given its UUID.+--+-- /Requires Linux 3.12 or later./+getSubvolByUuid+    :: FILEPATH -- ^ The mount point of the volume (or any file in that volume).+    -> UUID     -- ^ The UUID of the subvolume.+    -> IO SubvolId+getSubvolByUuid path uuid =+    withFd path ReadOnly $ \fd ->+        getSubvolByUuidFd fd uuid++getSubvolByReceivedUuidFd :: Fd -> UUID -> IO SubvolId+getSubvolByReceivedUuidFd =+    searchByUuidFd (#const BTRFS_UUID_KEY_RECEIVED_SUBVOL)++-- | Find the id of a subvolume, given its 'siReceivedUuid'.+--+-- /Requires Linux 3.12 or later./+getSubvolByReceivedUuid+    :: FILEPATH -- ^ The mount point of the volume (or any file in that volume).+    -> UUID     -- ^ The 'siReceivedUuid' of the subvolume.+    -> IO SubvolId+getSubvolByReceivedUuid path uuid =+    withFd path ReadOnly $ \fd ->+        getSubvolByReceivedUuidFd fd uuid++--------------------------------------------------------------------------------++defragFd :: Fd -> IO ()+defragFd fd =+    throwErrnoIfMinus1_ "defragFd" $+        withBlockSIGVTALRM $ -- this is probably a bad idea+            ioctl fd (#const BTRFS_IOC_DEFRAG) nullPtr++-- | Defrag a single file.+--+-- Note: calls the @BTRFS_IOC_DEFRAG@ @ioctl@.+defrag :: FILEPATH -> IO ()+defrag path = withFd path ReadWrite defragFd++--------------------------------------------------------------------------------++syncFd :: Fd -> IO ()+syncFd fd =+    throwErrnoIfMinus1_ "syncFd" $+        ioctl fd (#const BTRFS_IOC_SYNC) nullPtr++-- | Sync the file system identified by the supplied path.+-- The 'FilePath' can refer to any file in the file system.+--+-- Note: calls the @BTRFS_IOC_SYNC@ @ioctl@.+sync :: FILEPATH -> IO ()+sync path = withFd path ReadOnly syncFd++startSyncFd :: Fd -> IO ()+startSyncFd fd =+    throwErrnoIfMinus1_ "startSyncFd" $+        ioctl_fast fd (#const BTRFS_IOC_START_SYNC) nullPtr++-- | Initiate a sync for the file system identified by the supplied path.+--+-- Note: calls the @BTRFS_IOC_START_SYNC@ @ioctl@.+startSync :: FILEPATH -> IO ()+startSync path = withFd path ReadOnly startSyncFd++waitSyncFd :: Fd -> IO ()+waitSyncFd fd =+    throwErrnoIfMinus1_ "waitSyncFd" $+        ioctl fd (#const BTRFS_IOC_WAIT_SYNC) nullPtr++-- | Wait until the sync operation completes.+--+-- Note: calls the @BTRFS_IOC_WAIT_SYNC@ @ioctl@.+waitSync :: FILEPATH -> IO ()+waitSync path = withFd path ReadOnly waitSyncFd++--------------------------------------------------------------------------------++resolveLogicalFd :: Fd -> FileSize -> IO ([(InodeNum, FileSize, SubvolId)], Int)+resolveLogicalFd rootFd logical =+    allocaBytes inodesSize $ \inodes ->+    allocaBytesZero (#size struct btrfs_ioctl_logical_ino_args) $ \lia -> do+        (#poke struct btrfs_ioctl_logical_ino_args, logical) lia logical+        (#poke struct btrfs_ioctl_logical_ino_args, size   ) lia (fromIntegral inodesSize :: Word64)+        (#poke struct btrfs_ioctl_logical_ino_args, inodes ) lia inodes+        throwErrnoIfMinus1_ "resolveLogical" $ ioctl rootFd (#const BTRFS_IOC_LOGICAL_INO) lia+        elemMissed <- (#peek struct btrfs_data_container, elem_missed) inodes :: IO Word32+        count      <- (#peek struct btrfs_data_container, elem_cnt   ) inodes :: IO Word32+        let val = (#ptr struct btrfs_data_container, val) inodes :: Ptr Word64+        vals <- peekArray (fromIntegral count) val+        return (extractTriplets vals, fromIntegral elemMissed)+  where+    inodesSize = 64 * 1024 + (#size struct btrfs_data_container)+    extractTriplets (x1 : x2 : x3 : xs) = (x1, x2, x3) : extractTriplets xs+    extractTriplets [] = []+    extractTriplets _ = error "extractTriplets: The length of the list must be a multiple of 3"++-- | Given a physical offset, look for any inodes that this byte belongs+-- to. For each inode, it returns the inode number, the logical offset+-- (i.e. the offset within the inode), and the subvolume id. If a large+-- number of inodes is found, then not all of them will be returned by this+-- function. This is due to a current limitation in the kernel. The integer+-- returned along with list of inodes indicates the number of inodes found+-- but not included in the list.+--+-- Note: calls the @BTRFS_IOC_LOGICAL_INO@ @ioctl@.+resolveLogical+    :: FILEPATH -- ^ The mount point of the volume (or any file in that volume).+    -> FileSize -- ^ The physical byte offset in the underlying block device.+    -> IO ([(InodeNum, FileSize, SubvolId)], Int)+resolveLogical rootPath logical =+    withFd rootPath ReadOnly $ \fd ->+        resolveLogicalFd fd logical++resolveInodeFd :: Fd -> InodeNum -> IO ([FILEPATH], Int)+resolveInodeFd subvolFd inum =+    allocaBytes fspathSize $ \fspath ->+    allocaBytesZero (#size struct btrfs_ioctl_ino_path_args) $ \ipa -> do+        (#poke struct btrfs_ioctl_ino_path_args, inum  ) ipa inum+        (#poke struct btrfs_ioctl_ino_path_args, size  ) ipa (fromIntegral fspathSize :: Word64)+        (#poke struct btrfs_ioctl_ino_path_args, fspath) ipa fspath+        throwErrnoIfMinus1_ "resolveInode" $ ioctl subvolFd (#const BTRFS_IOC_INO_PATHS) ipa+        elemMissed <- (#peek struct btrfs_data_container, elem_missed) fspath :: IO Word32+        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+        return (paths, fromIntegral elemMissed)+  where+    fspathSize = 2 * 1024 + (#size struct btrfs_data_container)++-- | Find the file path(s) given an inode number. Returns a list of file paths+-- and an integer indicating the number of path found but not included in+-- the resulting list. This is because of a limitation in the kernel (it+-- will not return an arbitrarily large list). The paths returned are+-- relative to the root of the subvolume.+--+-- Note: calls the @BTRFS_IOC_INO_PATHS@ @ioctl@.+resolveInode+    :: FILEPATH -- ^ The path to the subvolume (or any file in that subvolume).+    -> InodeNum -- ^ The inode number.+    -> IO ([FILEPATH], Int)+resolveInode subvolPath inum =+    withFd subvolPath ReadOnly $ \subvolFd ->+        resolveInodeFd subvolFd inum++lookupInodeFd :: Fd -> SubvolId -> InodeNum -> IO (SubvolId, FILEPATH)+lookupInodeFd fd treeId inum =+    allocaBytesZero (#size struct btrfs_ioctl_ino_lookup_args) $ \ila -> do+        (#poke struct btrfs_ioctl_ino_lookup_args, treeid  ) ila treeId+        (#poke struct btrfs_ioctl_ino_lookup_args, objectid) ila inum+        throwErrnoIfMinus1_ "lookupInodeFd" $+            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+        return (treeId', dropTrailingSlash name)++-- | Find the path of a file given its inode number and the id of the+-- subvolume. If multiple files share the same inode number, only one of+-- them is returned. The id of the subvolume is also returned. This is+-- useful when 0 is given for the 'SubvolId' argument (also see+-- 'getSubvol' for this case).+--+-- Note: calls the @BTRFS_IOC_INO_LOOKUP@ @ioctl@.+lookupInode+    :: FILEPATH -- ^ The path to any file in the volume. The subvolume where+                -- this file resides is ignored unless no 'SubvolId' is+                -- provided (see below).+    -> SubvolId -- ^ The id of the subvolume. Can be 0. In that case, the+                -- subvolume of the 'FilePath' is used (see above).+    -> InodeNum -- ^ The inode number.+    -> IO (SubvolId, FILEPATH)+lookupInode path treeId inum =+    withFd path ReadOnly $ \fd -> lookupInodeFd fd treeId inum++--------------------------------------------------------------------------------++getFileNoCOWFd :: Fd -> IO Bool+getFileNoCOWFd fd =+    alloca $ \flagsPtr -> do+        throwErrnoIfMinus1_ "getFileNoCOWFd" $+            ioctl fd (#const FS_IOC_GETFLAGS) flagsPtr+        flags <- peek flagsPtr :: IO CUInt+        return (flags .&. (#const FS_NOCOW_FL) /= 0)++-- | Determine whether the NOCOW flag is enabled for the specified file.+--+-- Note: calls the @FS_IOC_GETFLAGS@ @ioctl@.+getFileNoCOW :: FILEPATH -> IO Bool+getFileNoCOW path =+    withFd path ReadOnly getFileNoCOWFd++setFileNoCOWFd :: Fd -> Bool -> IO ()+setFileNoCOWFd fd noCOW = do+    alloca $ \flagsPtr -> do+        throwErrnoIfMinus1_ "setFileNoCOWFd" $+            ioctl fd (#const FS_IOC_GETFLAGS) flagsPtr+        if noCOW then+            setFlags flagsPtr ((#const FS_NOCOW_FL) :: CUInt)+        else+            clearFlags flagsPtr ((#const FS_NOCOW_FL) :: CUInt)+        throwErrnoIfMinus1_ "setFileNoCOWFd" $+            ioctl fd (#const FS_IOC_SETFLAGS) flagsPtr++-- | Set or clear the NOCOW flag for the specified file. If the file is not+-- empty, this has no effect and no error will be reported.+--+-- Note: calls the @FS_IOC_GETFLAGS@ and @FS_IOC_GETFLAGS@ @ioctl@s.+setFileNoCOW :: FILEPATH -> Bool -> IO ()+setFileNoCOW path noCOW = do+    withFd path ReadOnly $ \fd ->+        setFileNoCOWFd fd noCOW++--------------------------------------------------------------------------------++data SearchKey = SearchKey+    { skTreeId      :: ObjectId+    , skMinObjectId :: ObjectId+    , skMinType     :: ObjectType+    , skMinOffset   :: Word64+    , skMaxObjectId :: ObjectId+    , skMaxType     :: ObjectType+    , skMaxOffset   :: Word64+    , skMinTransId  :: Word64+    , skMaxTransId  :: Word64+    }+  deriving (Show, Eq)++defaultSearchKey :: SearchKey+defaultSearchKey = SearchKey+    { skTreeId      = 0+    , skMinObjectId = minBound+    , skMinType     = minBound+    , skMinOffset   = minBound+    , skMaxObjectId = maxBound+    , skMaxType     = maxBound+    , skMaxOffset   = maxBound+    , skMinTransId  = minBound+    , skMaxTransId  = maxBound+    }++data SearchHeader = SearchHeader+    { shTransId  :: Word64+    , shObjectId :: ObjectId+    , shOffset   :: Word64+    , shType     :: ObjectType+    , shLen      :: Word32+    }+  deriving (Show, Eq)++treeSearchFd :: Fd -> SearchKey -> Int -> (SearchHeader -> Ptr i -> IO ()) -> IO ()+treeSearchFd fd sk maxItemCount0 callback =+    allocaBytesZero (#size struct btrfs_ioctl_search_args) $ \saPtr -> do+        let skPtr = (#ptr struct btrfs_ioctl_search_args, key) saPtr+        pokeSearchKey skPtr sk+        loopSingleSearch saPtr skPtr maxItemCount0+  where+    loopSingleSearch saPtr skPtr maxItemCount+        | maxItemCount <= 0 = return ()+        | otherwise = do+            let nrItems = fromIntegral (min 4096 maxItemCount) :: Word32+            (#poke struct btrfs_ioctl_search_key, nr_items) skPtr nrItems+            throwErrnoIfMinus1_ "treeSearchFd" $+                ioctl fd (#const BTRFS_IOC_TREE_SEARCH) saPtr+            itemsFound <- (#peek struct btrfs_ioctl_search_key, nr_items) skPtr :: IO Word32+            when (itemsFound > 0) $ do+                let shPtr = (#ptr struct btrfs_ioctl_search_args, buf) saPtr+                lastSh <- loopItems shPtr itemsFound+                case nextKey (shObjectId lastSh, shType lastSh, shOffset lastSh) of+                    Nothing -> return ()+                    Just (objectId, iType, offset) -> do+                        (#poke struct btrfs_ioctl_search_key, min_objectid) skPtr objectId+                        (#poke struct btrfs_ioctl_search_key, min_type    ) skPtr (fromIntegral iType :: Word32)+                        (#poke struct btrfs_ioctl_search_key, min_offset  ) skPtr offset+                        loopSingleSearch saPtr skPtr (maxItemCount - fromIntegral itemsFound)+    -- itemsFound must be at least 1+    loopItems shPtr itemsFound = do+        (sh, itemPtr) <- peekSearchItem shPtr+        callback sh itemPtr+        if itemsFound <= 1 then+            return sh+        else do+            let shPtr' = itemPtr `plusPtr` fromIntegral (shLen sh)+            loopItems shPtr' (itemsFound - 1)+    -- items are index by keys which are (objectId, iType, offset)+    -- they are returned in lexicographical order wrt the keys+    nextKey (objectId, iType, offset)+        | offset   < maxBound         = Just (objectId, iType, offset + 1)+        | iType    < skMaxType sk     = Just (objectId, iType + 1, skMinOffset sk)+        | objectId < skMaxObjectId sk = Just (objectId + 1, skMinType sk, skMinOffset sk)+        | otherwise                   = Nothing++treeSearch :: FILEPATH -> SearchKey -> Int -> (SearchHeader -> Ptr i -> IO ()) -> IO ()+treeSearch path sk maxItemCount callback =+    withFd path ReadOnly $ \fd ->+        treeSearchFd fd sk maxItemCount callback++treeSearchListFd :: Fd -> SearchKey -> (SearchHeader -> Ptr i -> IO (Maybe a)) -> IO [a]+treeSearchListFd fd sk unpack = do+    res <- newIORef []+    treeSearchFd fd sk maxBound $ \sh itemPtr -> do+        r <- unpack sh itemPtr+        case r of+            Nothing -> return ()+            Just x -> modifyIORef' res (x :)+    liftM reverse $ readIORef res++treeSearchList :: FILEPATH -> SearchKey -> (SearchHeader -> Ptr i -> IO (Maybe a)) -> IO [a]+treeSearchList path sk unpack =+    withFd path ReadOnly $ \fd ->+        treeSearchListFd fd sk unpack++findFirstItemFd :: Fd -> SearchKey -> (SearchHeader -> Ptr i -> IO a) -> IO a+findFirstItemFd fd sk unpack = do+    res <- newIORef Nothing+    treeSearchFd fd sk 1 $ \sh ptr -> do+        r <- unpack sh ptr+        modifyIORef' res (`mplus` Just r)+    resV <- readIORef res+    case resV of+        Just x -> return x+        Nothing ->+            ioError $ mkIOError doesNotExistErrorType+                                "findFirstItemFd"+                                Nothing Nothing++findFirstItem :: FILEPATH -> SearchKey -> (SearchHeader -> Ptr i -> IO a) -> IO a+findFirstItem path sk unpack =+    withFd path ReadOnly $ \fd ->+        findFirstItemFd fd sk unpack++-- does not initialize nr_items+pokeSearchKey :: Ptr a -> SearchKey -> IO ()+pokeSearchKey ptr sk = do+    (#poke struct btrfs_ioctl_search_key, tree_id     ) ptr (skTreeId      sk)+    (#poke struct btrfs_ioctl_search_key, min_objectid) ptr (skMinObjectId sk)+    (#poke struct btrfs_ioctl_search_key, min_type    ) ptr (fromIntegral (skMinType sk) :: Word32)+    (#poke struct btrfs_ioctl_search_key, min_offset  ) ptr (skMinOffset   sk)+    (#poke struct btrfs_ioctl_search_key, max_objectid) ptr (skMaxObjectId sk)+    (#poke struct btrfs_ioctl_search_key, max_type    ) ptr (fromIntegral (skMaxType sk) :: Word32)+    (#poke struct btrfs_ioctl_search_key, max_offset  ) ptr (skMaxOffset   sk)+    (#poke struct btrfs_ioctl_search_key, min_transid ) ptr (skMinTransId  sk)+    (#poke struct btrfs_ioctl_search_key, max_transid ) ptr (skMaxTransId  sk)++peekSearchItem :: Ptr a -> IO (SearchHeader, Ptr i)+peekSearchItem shPtr = do+    transId  <- (#peek struct btrfs_ioctl_search_header, transid ) shPtr :: IO Word64+    objectId <- (#peek struct btrfs_ioctl_search_header, objectid) shPtr :: IO Word64+    offset   <- (#peek struct btrfs_ioctl_search_header, offset  ) shPtr :: IO Word64+    iType    <- (#peek struct btrfs_ioctl_search_header, type    ) shPtr :: IO Word32+    len      <- (#peek struct btrfs_ioctl_search_header, len     ) shPtr :: IO Word32+    let itemPtr = shPtr `plusPtr` (#size struct btrfs_ioctl_search_header)+    return (SearchHeader transId objectId offset (fromIntegral iType) len, itemPtr)++peekRootRef :: Ptr a -> IO (InodeNum, FILEPATH)+peekRootRef rrPtr = do+    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)+    return (dirId, name)++--------------------------------------------------------------------------------++withFd :: FILEPATH -> OpenMode -> (Fd -> IO r) -> IO r+withFd path openMode action =+    bracket (openFd path openMode Nothing defaultFileFlags {nonBlock = True})+            closeFd action++withSplitPathOpenParent :: String -> Int -> FILEPATH -> (CStringLen -> Fd -> IO r) -> IO r+withSplitPathOpenParent loc maxLen path action =+    unsafeWithCStringLen 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+{-# INLINE nothingIf #-}++modifyPtr :: Storable a => Ptr a -> (a -> a) -> IO ()+modifyPtr ptr f = do+    peek ptr >>= (poke ptr . f)++setFlags :: (Storable a, Bits a) => Ptr a -> a -> IO ()+setFlags ptr flags =+    modifyPtr ptr (.|. flags)++clearFlags :: (Storable a, Bits a) => Ptr a -> a -> IO ()+clearFlags ptr flags =+    modifyPtr ptr (.&. complement flags)++allocaBytesZero :: Int -> (Ptr a -> IO b) -> IO b+allocaBytesZero size action =+    allocaBytes size $ \ptr -> do+        memset ptr 0 size+        action ptr++memset :: Ptr a -> Word8 -> Int -> IO ()+memset p b l = do+    _ <- c_memset p (fromIntegral b) (fromIntegral l)+    return ()+{-# INLINE memset #-}++foreign import ccall unsafe "string.h memset"+    c_memset :: Ptr a -> CInt -> CSize -> IO (Ptr a)
+ System/Linux/Btrfs/FilePathLike.hs view
@@ -0,0 +1,87 @@+{-# LANGUAGE FlexibleInstances #-}++module System.Linux.Btrfs.FilePathLike+    ( FilePathLike(..)+    , RawFilePath+    ) where++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 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.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)++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 +    openFd :: s -> OpenMode -> Maybe FileMode -> OpenFileFlags -> IO Fd+    dropTrailingSlash :: s -> s+    (</>) :: s -> s -> s+    splitFileName :: s -> (s, s)++instance FilePathLike [Char] where+    asString = id+    peekCString = S.peekCString+    peekCStringLen = S.peekCStringLen+    withCString = S.withCString+    withCStringLen = S.withCStringLen+    unsafeWithCStringLen = withCStringLen+    openFd = S.openFd+    dropTrailingSlash s = if null s' then "/" else s'+      where+        s' = dropWhileEnd (== '/') s+    _ </> s2@('/' : _) = s2+    s1 </> "" = s1+    "" </> s2 = s2+    s1 </> s2 = if s1' == "/" then '/' : s2 else s1' ++ "/" ++ s2+      where+        s1' = dropTrailingSlash s1+    splitFileName s = (if null d then "./" else reverse d, reverse n)+      where+        (n, d) = span (/= '/') $ reverse s++instance FilePathLike B.ByteString where+    asString = convert+    peekCString = B.packCString+    peekCStringLen = B.packCStringLen+    withCString = B.useAsCString+    withCStringLen = B.useAsCStringLen+    unsafeWithCStringLen = B.unsafeUseAsCStringLen+    openFd = B.openFd+    dropTrailingSlash s = if B.null s' then slashBS else s'+      where+        (s', _) = B8.spanEnd (== '/') s+    s1 </> s2+        | B.null s1 = s2+        | B.null s2 = s1+        | B8.head s2 == '/' = s2+        | otherwise =+            let s1' = dropTrailingSlash s1+            in  if B8.last s1' == '/' then slashBS <> s2+                                      else B.concat [s1', slashBS, s2]+    splitFileName s = (if B.null d then curDir else d, n)+      where+        (d, n) = B8.spanEnd (/= '/') s+        curDir = B8.pack "./"++convert :: (FilePathLike s1, FilePathLike s2) => s1 -> s2+convert s = unsafePerformIO $ unsafeWithCStringLen s peekCStringLen++slashBS :: B.ByteString+slashBS = B8.singleton '/'
+ System/Linux/Btrfs/Time.hsc view
@@ -0,0 +1,27 @@+module System.Linux.Btrfs.Time+    ( BtrfsTime(..)+    ) where++import Data.Time.Format ()+import Data.Time.Clock (UTCTime)+import Data.Time.Clock.POSIX (posixSecondsToUTCTime)+import Data.Word.Endian (LE32(..), LE64(..))+import Data.Ratio ((%))++import Foreign.Storable (Storable(..))+import Foreign.C.Types (CInt)++#include <btrfs/ctree.h>++newtype BtrfsTime = BtrfsTime UTCTime++instance Storable BtrfsTime where+    sizeOf _ = (#size struct btrfs_timespec)+    alignment _ = alignment (undefined :: CInt)+    poke _ _ = error "not implemented"+    peek ptr = do+        LE64 sec  <- (#peek struct btrfs_timespec, sec ) ptr+        LE32 nsec <- (#peek struct btrfs_timespec, nsec) ptr+        let frac = toInteger nsec % 1000000000+        return $ BtrfsTime $ posixSecondsToUTCTime $+            fromRational $ toRational sec + frac
+ System/Linux/Btrfs/UUID.hs view
@@ -0,0 +1,62 @@+module System.Linux.Btrfs.UUID+    ( UUID(..)+    , toString+    , fromString+    ) where++import Data.Word (Word64)+import Data.Word.Endian (BE64(..))+import Data.Bits ((.&.), unsafeShiftR)+import Text.Printf (printf)++import Foreign.Storable (Storable(..))+import Foreign.Ptr (castPtr)+import Foreign.C.Types (CInt)++-- | A @UUID@ is stored as two big-endian 'Word64's.+data UUID = UUID Word64 Word64+  deriving (Eq, Ord)++instance Show UUID where+    showsPrec p u =+        showParen (p > 9) $+            showString "fromString " . shows (toString u)++instance Storable UUID where+    sizeOf _ = 16+    alignment _ = alignment (undefined :: CInt)+    peek ptr = do+        BE64 h  <- peek (castPtr ptr)+        BE64 l  <- peekByteOff ptr 8+        return $ UUID h l+    poke ptr (UUID h l) = do+        poke (castPtr ptr) (BE64 h)+        pokeByteOff ptr 8 (BE64 l)++toString :: UUID -> String+toString (UUID h l) = printf "%.8x-%.4x-%.4x-%.4x-%.12x" h1 h2 h3 l1 l2+  where+    h1 = (h .&. 0xffffffff00000000) `unsafeShiftR` 32+    h2 = (h .&.         0xffff0000) `unsafeShiftR` 16+    h3 = (h .&.             0xffff)+    l1 = (l .&. 0xffff000000000000) `unsafeShiftR` 48+    l2 = (l .&.     0xffffffffffff)++fromString :: String -> Maybe UUID+fromString s+    | isValidUUID s = Just $ UUID h l+    | otherwise = Nothing+  where+    h = read $ '0' : 'x' : take 16 s'+    l = read $ '0' : 'x' : drop 16 s'+    s' = filter (/= '-') s++isValidUUID :: String -> Bool+isValidUUID = and . zipWith checkChar [0..]+  where+    checkChar i c =+        if i `elem` hyphenPosns then+            c == '-'+        else+            c `elem` "0123456789abcdefABCDEF"+    hyphenPosns = [8, 13, 18, 23] :: [Int]
+ btrfs.cabal view
@@ -0,0 +1,82 @@+name:                btrfs+version:             0.1.0.0+synopsis:            Bindings to the btrfs API+description:+  This package provides low-level bindings to the btrfs API (i.e. the+  @BTRFS_IOC_@* @ioctl@s). Currently, only a subset of the API is+  supported, including functions needed to work with subvolumes/snapshots+  as well as file cloning.+  .+  In order to build this package, you need to @linux-headers 3.9@ or newer.+  .+  Warning: btrfs is still considered experimental. This module is also+  experimental and may contain serious bugs that may result in data loss.+  Do not use it on data that has not been backed up yet.+homepage:            https://github.com/redneb/hs-btrfs+bug-reports:         https://github.com/redneb/hs-btrfs/issues+license:             BSD3+license-file:        LICENSE+author:              Marios Titas <rednebΑΤgmxDΟΤcom>+maintainer:          Marios Titas <rednebΑΤgmxDΟΤcom>+category:            System, Filesystem+build-type:          Custom+cabal-version:       >=1.10++extra-source-files:+  include/btrfs/ctree.h+  include/btrfs/extent-cache.h+  include/btrfs/extent_io.h+  include/btrfs/ioctl.h+  include/btrfs/kerncompat.h+  include/btrfs/list.h+  include/btrfs/radix-tree.h+  include/btrfs/rbtree.h++source-repository head+  type: git+  location: https://github.com/redneb/hs-btrfs.git++flag examples+  description:         Build examples+  default:             False++library+  exposed-modules:     System.Linux.Btrfs, System.Linux.Btrfs.UUID+  other-modules:       Data.Word.Endian, System.Linux.Btrfs.Time,+                       System.Linux.Btrfs.FilePathLike+  build-depends:       base >=4.6 && <5, unix >=2.6,+                       time >=1.4, bytestring >=0.9+  include-dirs:        include+  build-tools:         hsc2hs+  default-language:    Haskell2010+  ghc-options:         -Wall++executable btrfs-defrag+  hs-source-dirs:      examples+  main-is:             btrfs-defrag.hs+  if !flag(examples)+    buildable:           False+  else+    build-depends:       base >=4.6 && <5, btrfs, unix, filepath+    default-language:    Haskell2010+    ghc-options:         -Wall++executable btrfs-clone-range+  hs-source-dirs:      examples+  main-is:             btrfs-clone-range.hs+  if !flag(examples)+    buildable:           False+  else+    build-depends:       base >=4.6 && <5, btrfs+    default-language:    Haskell2010+    ghc-options:         -Wall++executable btrfs-list-subvols+  hs-source-dirs:      examples+  main-is:             btrfs-list-subvols.hs+  if !flag(examples)+    buildable:           False+  else+    build-depends:       base >=4.6 && <5, btrfs+    default-language:    Haskell2010+    ghc-options:         -Wall
+ examples/btrfs-clone-range.hs view
@@ -0,0 +1,9 @@+import System.Environment++import System.Linux.Btrfs++main :: IO ()+main = do+    [srcPath, srcOff, srcLen, dstPath, dstOff] <- getArgs+    cloneRange srcPath (read srcOff) (read srcLen)+               dstPath (read dstOff)
+ examples/btrfs-defrag.hs view
@@ -0,0 +1,41 @@+import Control.Monad+import Control.Monad.Fix+import Control.Exception+import System.Posix+import System.Environment+import System.FilePath+import System.IO++import System.Linux.Btrfs++main :: IO ()+main = do+    paths <- getArgs+    mapM_ defragRec paths++defragRec :: FilePath -> IO ()+defragRec path0 =+    traverseTree path0 $ \path stat ->+        when (isRegularFile stat) $+            handleIOExn $ defrag path++traverseTree :: FilePath -> (FilePath -> FileStatus -> IO ()) -> IO ()+traverseTree path action = do+    stat <- getSymbolicLinkStatus path+    action path stat+    when (isDirectory stat) $ do+        loopDir path $ \s ->+            traverseTree (path </> s) action++loopDir :: FilePath -> (FilePath -> IO ()) -> IO ()+loopDir path action = do+    bracket (openDirStream path) closeDirStream $ \dir ->+        fix $ \loop -> do+            s <- readDirStream dir+            unless (null s) $ do+                unless (s == "." || s == "..") $ action s+                loop++handleIOExn :: IO () -> IO ()+handleIOExn =+    handle (\e -> hPrint stderr (e ::  IOException))
+ examples/btrfs-list-subvols.hs view
@@ -0,0 +1,15 @@+import System.Environment+import Control.Monad++import System.Linux.Btrfs++main :: IO ()+main = do+    paths <- getArgs+    forM_ paths $ \path -> do+        subvols <- listSubvolPaths path+        putStrLn (path ++ ":")+        forM_ subvols $ \(subvolId, parentId, subvolPath) ->+            putStrLn ("\t" ++ show subvolId +++                      "\t" ++ show parentId +++                      "\t" ++ subvolPath)
+ include/btrfs/ctree.h view
@@ -0,0 +1,2385 @@+/*+ * Copyright (C) 2007 Oracle.  All rights reserved.+ *+ * This program is free software; you can redistribute it and/or+ * modify it under the terms of the GNU General Public+ * License v2 as published by the Free Software Foundation.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU+ * General Public License for more details.+ *+ * You should have received a copy of the GNU General Public+ * License along with this program; if not, write to the+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,+ * Boston, MA 021110-1307, USA.+ */++#ifndef __BTRFS__+#define __BTRFS__++#if BTRFS_FLAT_INCLUDES+#include "list.h"+#include "kerncompat.h"+#include "radix-tree.h"+#include "extent-cache.h"+#include "extent_io.h"+#include "ioctl.h"+#else+#include <btrfs/list.h>+#include <btrfs/kerncompat.h>+#include <btrfs/radix-tree.h>+#include <btrfs/extent-cache.h>+#include <btrfs/extent_io.h>+#include <btrfs/ioctl.h>+#endif /* BTRFS_FLAT_INCLUDES */++struct btrfs_root;+struct btrfs_trans_handle;+struct btrfs_free_space_ctl;+#define BTRFS_MAGIC 0x4D5F53665248425FULL /* ascii _BHRfS_M, no null */++#define BTRFS_MAX_LEVEL 8++#define BTRFS_COMPAT_EXTENT_TREE_V0++/* holds pointers to all of the tree roots */+#define BTRFS_ROOT_TREE_OBJECTID 1ULL++/* stores information about which extents are in use, and reference counts */+#define BTRFS_EXTENT_TREE_OBJECTID 2ULL++/*+ * chunk tree stores translations from logical -> physical block numbering+ * the super block points to the chunk tree+ */+#define BTRFS_CHUNK_TREE_OBJECTID 3ULL++/*+ * stores information about which areas of a given device are in use.+ * one per device.  The tree of tree roots points to the device tree+ */+#define BTRFS_DEV_TREE_OBJECTID 4ULL++/* one per subvolume, storing files and directories */+#define BTRFS_FS_TREE_OBJECTID 5ULL++/* directory objectid inside the root tree */+#define BTRFS_ROOT_TREE_DIR_OBJECTID 6ULL+/* holds checksums of all the data extents */+#define BTRFS_CSUM_TREE_OBJECTID 7ULL+#define BTRFS_QUOTA_TREE_OBJECTID 8ULL++/* for storing items that use the BTRFS_UUID_KEY* */+#define BTRFS_UUID_TREE_OBJECTID 9ULL++/* for storing balance parameters in the root tree */+#define BTRFS_BALANCE_OBJECTID -4ULL++/* oprhan objectid for tracking unlinked/truncated files */+#define BTRFS_ORPHAN_OBJECTID -5ULL++/* does write ahead logging to speed up fsyncs */+#define BTRFS_TREE_LOG_OBJECTID -6ULL+#define BTRFS_TREE_LOG_FIXUP_OBJECTID -7ULL++/* space balancing */+#define BTRFS_TREE_RELOC_OBJECTID -8ULL+#define BTRFS_DATA_RELOC_TREE_OBJECTID -9ULL++/*+ * extent checksums all have this objectid+ * this allows them to share the logging tree+ * for fsyncs+ */+#define BTRFS_EXTENT_CSUM_OBJECTID -10ULL++/* For storing free space cache */+#define BTRFS_FREE_SPACE_OBJECTID -11ULL++/*+ * The inode number assigned to the special inode for sotring+ * free ino cache+ */+#define BTRFS_FREE_INO_OBJECTID -12ULL++/* dummy objectid represents multiple objectids */+#define BTRFS_MULTIPLE_OBJECTIDS -255ULL++/*+ * All files have objectids in this range.+ */+#define BTRFS_FIRST_FREE_OBJECTID 256ULL+#define BTRFS_LAST_FREE_OBJECTID -256ULL+#define BTRFS_FIRST_CHUNK_TREE_OBJECTID 256ULL++++/*+ * the device items go into the chunk tree.  The key is in the form+ * [ 1 BTRFS_DEV_ITEM_KEY device_id ]+ */+#define BTRFS_DEV_ITEMS_OBJECTID 1ULL++/*+ * the max metadata block size.  This limit is somewhat artificial,+ * but the memmove costs go through the roof for larger blocks.+ */+#define BTRFS_MAX_METADATA_BLOCKSIZE 65536++/*+ * we can actually store much bigger names, but lets not confuse the rest+ * of linux+ */+#define BTRFS_NAME_LEN 255++/*+ * Theoretical limit is larger, but we keep this down to a sane+ * value. That should limit greatly the possibility of collisions on+ * inode ref items.+ */+#define	BTRFS_LINK_MAX	65535U++/* 32 bytes in various csum fields */+#define BTRFS_CSUM_SIZE 32++/* csum types */+#define BTRFS_CSUM_TYPE_CRC32	0++static int btrfs_csum_sizes[] = { 4, 0 };++/* four bytes for CRC32 */+#define BTRFS_CRC32_SIZE 4+#define BTRFS_EMPTY_DIR_SIZE 0++#define BTRFS_FT_UNKNOWN	0+#define BTRFS_FT_REG_FILE	1+#define BTRFS_FT_DIR		2+#define BTRFS_FT_CHRDEV		3+#define BTRFS_FT_BLKDEV		4+#define BTRFS_FT_FIFO		5+#define BTRFS_FT_SOCK		6+#define BTRFS_FT_SYMLINK	7+#define BTRFS_FT_XATTR		8+#define BTRFS_FT_MAX		9++#define BTRFS_ROOT_SUBVOL_RDONLY	(1ULL << 0)++/*+ * the key defines the order in the tree, and so it also defines (optimal)+ * block layout.  objectid corresonds to the inode number.  The flags+ * tells us things about the object, and is a kind of stream selector.+ * so for a given inode, keys with flags of 1 might refer to the inode+ * data, flags of 2 may point to file data in the btree and flags == 3+ * may point to extents.+ *+ * offset is the starting byte offset for this key in the stream.+ *+ * btrfs_disk_key is in disk byte order.  struct btrfs_key is always+ * in cpu native order.  Otherwise they are identical and their sizes+ * should be the same (ie both packed)+ */+struct btrfs_disk_key {+	__le64 objectid;+	u8 type;+	__le64 offset;+} __attribute__ ((__packed__));++struct btrfs_key {+	u64 objectid;+	u8 type;+	u64 offset;+} __attribute__ ((__packed__));++struct btrfs_mapping_tree {+	struct cache_tree cache_tree;+};++#define BTRFS_UUID_SIZE 16+struct btrfs_dev_item {+	/* the internal btrfs device id */+	__le64 devid;++	/* size of the device */+	__le64 total_bytes;++	/* bytes used */+	__le64 bytes_used;++	/* optimal io alignment for this device */+	__le32 io_align;++	/* optimal io width for this device */+	__le32 io_width;++	/* minimal io size for this device */+	__le32 sector_size;++	/* type and info about this device */+	__le64 type;++	/* expected generation for this device */+	__le64 generation;++	/*+	 * starting byte of this partition on the device,+	 * to allowr for stripe alignment in the future+	 */+	__le64 start_offset;++	/* grouping information for allocation decisions */+	__le32 dev_group;++	/* seek speed 0-100 where 100 is fastest */+	u8 seek_speed;++	/* bandwidth 0-100 where 100 is fastest */+	u8 bandwidth;++	/* btrfs generated uuid for this device */+	u8 uuid[BTRFS_UUID_SIZE];++	/* uuid of FS who owns this device */+	u8 fsid[BTRFS_UUID_SIZE];+} __attribute__ ((__packed__));++struct btrfs_stripe {+	__le64 devid;+	__le64 offset;+	u8 dev_uuid[BTRFS_UUID_SIZE];+} __attribute__ ((__packed__));++struct btrfs_chunk {+	/* size of this chunk in bytes */+	__le64 length;++	/* objectid of the root referencing this chunk */+	__le64 owner;++	__le64 stripe_len;+	__le64 type;++	/* optimal io alignment for this chunk */+	__le32 io_align;++	/* optimal io width for this chunk */+	__le32 io_width;++	/* minimal io size for this chunk */+	__le32 sector_size;++	/* 2^16 stripes is quite a lot, a second limit is the size of a single+	 * item in the btree+	 */+	__le16 num_stripes;++	/* sub stripes only matter for raid10 */+	__le16 sub_stripes;+	struct btrfs_stripe stripe;+	/* additional stripes go here */+} __attribute__ ((__packed__));++#define BTRFS_FREE_SPACE_EXTENT	1+#define BTRFS_FREE_SPACE_BITMAP	2++struct btrfs_free_space_entry {+	__le64 offset;+	__le64 bytes;+	u8 type;+} __attribute__ ((__packed__));++struct btrfs_free_space_header {+	struct btrfs_disk_key location;+	__le64 generation;+	__le64 num_entries;+	__le64 num_bitmaps;+} __attribute__ ((__packed__));++static inline unsigned long btrfs_chunk_item_size(int num_stripes)+{+	BUG_ON(num_stripes == 0);+	return sizeof(struct btrfs_chunk) ++		sizeof(struct btrfs_stripe) * (num_stripes - 1);+}++#define BTRFS_HEADER_FLAG_WRITTEN		(1ULL << 0)+#define BTRFS_HEADER_FLAG_RELOC			(1ULL << 1)+#define BTRFS_SUPER_FLAG_SEEDING		(1ULL << 32)+#define BTRFS_SUPER_FLAG_METADUMP		(1ULL << 33)++#define BTRFS_BACKREF_REV_MAX		256+#define BTRFS_BACKREF_REV_SHIFT		56+#define BTRFS_BACKREF_REV_MASK		(((u64)BTRFS_BACKREF_REV_MAX - 1) << \+					 BTRFS_BACKREF_REV_SHIFT)++#define BTRFS_OLD_BACKREF_REV		0+#define BTRFS_MIXED_BACKREF_REV		1++/*+ * every tree block (leaf or node) starts with this header.+ */+struct btrfs_header {+	/* these first four must match the super block */+	u8 csum[BTRFS_CSUM_SIZE];+	u8 fsid[BTRFS_FSID_SIZE]; /* FS specific uuid */+	__le64 bytenr; /* which block this node is supposed to live in */+	__le64 flags;++	/* allowed to be different from the super from here on down */+	u8 chunk_tree_uuid[BTRFS_UUID_SIZE];+	__le64 generation;+	__le64 owner;+	__le32 nritems;+	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->leafsize))+#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))+++/*+ * this is a very generous portion of the super block, giving us+ * room to translate 14 chunks with 3 stripes each.+ */+#define BTRFS_SYSTEM_CHUNK_ARRAY_SIZE 2048+#define BTRFS_LABEL_SIZE 256++/*+ * just in case we somehow lose the roots and are not able to mount,+ * we store an array of the roots from previous transactions+ * in the super.+ */+#define BTRFS_NUM_BACKUP_ROOTS 4+struct btrfs_root_backup {+	__le64 tree_root;+	__le64 tree_root_gen;++	__le64 chunk_root;+	__le64 chunk_root_gen;++	__le64 extent_root;+	__le64 extent_root_gen;++	__le64 fs_root;+	__le64 fs_root_gen;++	__le64 dev_root;+	__le64 dev_root_gen;++	__le64 csum_root;+	__le64 csum_root_gen;++	__le64 total_bytes;+	__le64 bytes_used;+	__le64 num_devices;+	/* future */+	__le64 unsed_64[4];++	u8 tree_root_level;+	u8 chunk_root_level;+	u8 extent_root_level;+	u8 fs_root_level;+	u8 dev_root_level;+	u8 csum_root_level;+	/* future and to align */+	u8 unused_8[10];+} __attribute__ ((__packed__));++/*+ * the super block basically lists the main trees of the FS+ * it currently lacks any block count etc etc+ */+struct btrfs_super_block {+	u8 csum[BTRFS_CSUM_SIZE];+	/* the first 3 fields must match struct btrfs_header */+	u8 fsid[BTRFS_FSID_SIZE];    /* FS specific uuid */+	__le64 bytenr; /* this block number */+	__le64 flags;++	/* allowed to be different from the btrfs_header from here own down */+	__le64 magic;+	__le64 generation;+	__le64 root;+	__le64 chunk_root;+	__le64 log_root;++	/* this will help find the new super based on the log root */+	__le64 log_root_transid;+	__le64 total_bytes;+	__le64 bytes_used;+	__le64 root_dir_objectid;+	__le64 num_devices;+	__le32 sectorsize;+	__le32 nodesize;+	__le32 leafsize;+	__le32 stripesize;+	__le32 sys_chunk_array_size;+	__le64 chunk_root_generation;+	__le64 compat_flags;+	__le64 compat_ro_flags;+	__le64 incompat_flags;+	__le16 csum_type;+	u8 root_level;+	u8 chunk_root_level;+	u8 log_root_level;+	struct btrfs_dev_item dev_item;++	char label[BTRFS_LABEL_SIZE];++	__le64 cache_generation;+	__le64 uuid_tree_generation;++	/* future expansion */+	__le64 reserved[30];+	u8 sys_chunk_array[BTRFS_SYSTEM_CHUNK_ARRAY_SIZE];+	struct btrfs_root_backup super_roots[BTRFS_NUM_BACKUP_ROOTS];+} __attribute__ ((__packed__));++/*+ * Compat flags that we support.  If any incompat flags are set other than the+ * ones specified below then we will fail to mount+ */+#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)++/*+ * older kernels tried to do bigger metadata blocks, but the+ * code was pretty buggy.  Lets not let them try anymore.+ */+#define BTRFS_FEATURE_INCOMPAT_BIG_METADATA     (1ULL << 5)+#define BTRFS_FEATURE_INCOMPAT_EXTENDED_IREF	(1ULL << 6)+#define BTRFS_FEATURE_INCOMPAT_RAID56		(1ULL << 7)+#define BTRFS_FEATURE_INCOMPAT_SKINNY_METADATA	(1ULL << 8)+#define BTRFS_FEATURE_INCOMPAT_NO_HOLES		(1ULL << 9)+++#define BTRFS_FEATURE_COMPAT_SUPP		0ULL+#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_BIG_METADATA |		\+	 BTRFS_FEATURE_INCOMPAT_EXTENDED_IREF |		\+	 BTRFS_FEATURE_INCOMPAT_RAID56 |		\+	 BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS |		\+	 BTRFS_FEATURE_INCOMPAT_SKINNY_METADATA |	\+	 BTRFS_FEATURE_INCOMPAT_NO_HOLES)++/*+ * A leaf is full of items. offset and size tell us where to find+ * the item in the leaf (relative to the start of the data area)+ */+struct btrfs_item {+	struct btrfs_disk_key key;+	__le32 offset;+	__le32 size;+} __attribute__ ((__packed__));++/*+ * leaves have an item area and a data area:+ * [item0, item1....itemN] [free space] [dataN...data1, data0]+ *+ * The data is separate from the items to get the keys closer together+ * during searches.+ */+struct btrfs_leaf {+	struct btrfs_header header;+	struct btrfs_item items[];+} __attribute__ ((__packed__));++/*+ * all non-leaf blocks are nodes, they hold only keys and pointers to+ * other blocks+ */+struct btrfs_key_ptr {+	struct btrfs_disk_key key;+	__le64 blockptr;+	__le64 generation;+} __attribute__ ((__packed__));++struct btrfs_node {+	struct btrfs_header header;+	struct btrfs_key_ptr ptrs[];+} __attribute__ ((__packed__));++/*+ * btrfs_paths remember the path taken from the root down to the leaf.+ * level 0 is always the leaf, and nodes[1...BTRFS_MAX_LEVEL] will point+ * to any other levels that are present.+ *+ * The slots array records the index of the item or block pointer+ * used while walking the tree.+ */++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 */+	int locks[BTRFS_MAX_LEVEL];+	int reada;+	/* keep some upper locks as we walk down */+	int 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 keep_locks:1;+	unsigned int skip_locking:1;+	unsigned int leave_spinning:1;+	unsigned int skip_check_block:1;+};++/*+ * items in the extent btree are used to record the objectid of the+ * owner of the block and the number of references+ */++struct btrfs_extent_item {+	__le64 refs;+	__le64 generation;+	__le64 flags;+} __attribute__ ((__packed__));++struct btrfs_extent_item_v0 {+	__le32 refs;+} __attribute__ ((__packed__));++#define BTRFS_MAX_EXTENT_ITEM_SIZE(r) ((BTRFS_LEAF_DATA_SIZE(r) >> 4) - \+					sizeof(struct btrfs_item))++#define BTRFS_EXTENT_FLAG_DATA		(1ULL << 0)+#define BTRFS_EXTENT_FLAG_TREE_BLOCK	(1ULL << 1)++/* following flags only apply to tree blocks */++/* use full backrefs for extent pointers in the block*/+#define BTRFS_BLOCK_FLAG_FULL_BACKREF	(1ULL << 8)++struct btrfs_tree_block_info {+	struct btrfs_disk_key key;+	u8 level;+} __attribute__ ((__packed__));++struct btrfs_extent_data_ref {+	__le64 root;+	__le64 objectid;+	__le64 offset;+	__le32 count;+} __attribute__ ((__packed__));++struct btrfs_shared_data_ref {+	__le32 count;+} __attribute__ ((__packed__));++struct btrfs_extent_inline_ref {+	u8 type;+	__le64 offset;+} __attribute__ ((__packed__));++struct btrfs_extent_ref_v0 {+	__le64 root;+	__le64 generation;+	__le64 objectid;+	__le32 count;+} __attribute__ ((__packed__));++/* dev extents record free space on individual devices.  The owner+ * field points back to the chunk allocation mapping tree that allocated+ * the extent.  The chunk tree uuid field is a way to double check the owner+ */+struct btrfs_dev_extent {+	__le64 chunk_tree;+	__le64 chunk_objectid;+	__le64 chunk_offset;+	__le64 length;+	u8 chunk_tree_uuid[BTRFS_UUID_SIZE];+} __attribute__ ((__packed__));++struct btrfs_inode_ref {+	__le64 index;+	__le16 name_len;+	/* name goes here */+} __attribute__ ((__packed__));++struct btrfs_inode_extref {+	__le64 parent_objectid;+	__le64 index;+	__le16 name_len;+	__u8   name[0]; /* name goes here */+} __attribute__ ((__packed__));++struct btrfs_timespec {+	__le64 sec;+	__le32 nsec;+} __attribute__ ((__packed__));++typedef enum {+	BTRFS_COMPRESS_NONE  = 0,+	BTRFS_COMPRESS_ZLIB  = 1,+	BTRFS_COMPRESS_LZO   = 2,+	BTRFS_COMPRESS_TYPES = 2,+	BTRFS_COMPRESS_LAST  = 3,+} btrfs_compression_type;++/* we don't understand any encryption methods right now */+typedef enum {+	BTRFS_ENCRYPTION_NONE = 0,+	BTRFS_ENCRYPTION_LAST = 1,+} btrfs_encryption_type;++enum btrfs_tree_block_status {+	BTRFS_TREE_BLOCK_CLEAN,+	BTRFS_TREE_BLOCK_INVALID_NRITEMS,+	BTRFS_TREE_BLOCK_INVALID_PARENT_KEY,+	BTRFS_TREE_BLOCK_BAD_KEY_ORDER,+	BTRFS_TREE_BLOCK_INVALID_LEVEL,+	BTRFS_TREE_BLOCK_INVALID_FREE_SPACE,+	BTRFS_TREE_BLOCK_INVALID_OFFSETS,+};++struct btrfs_inode_item {+	/* nfs style generation number */+	__le64 generation;+	/* transid that last touched this inode */+	__le64 transid;+	__le64 size;+	__le64 nbytes;+	__le64 block_group;+	__le32 nlink;+	__le32 uid;+	__le32 gid;+	__le32 mode;+	__le64 rdev;+	__le64 flags;++	/* modification sequence number for NFS */+	__le64 sequence;++	/*+	 * a little future expansion, for more than this we can+	 * just grow the inode item and version it+	 */+	__le64 reserved[4];+	struct btrfs_timespec atime;+	struct btrfs_timespec ctime;+	struct btrfs_timespec mtime;+	struct btrfs_timespec otime;+} __attribute__ ((__packed__));++struct btrfs_dir_log_item {+	__le64 end;+} __attribute__ ((__packed__));++struct btrfs_dir_item {+	struct btrfs_disk_key location;+	__le64 transid;+	__le16 data_len;+	__le16 name_len;+	u8 type;+} __attribute__ ((__packed__));++struct btrfs_root_item_v0 {+	struct btrfs_inode_item inode;+	__le64 generation;+	__le64 root_dirid;+	__le64 bytenr;+	__le64 byte_limit;+	__le64 bytes_used;+	__le64 last_snapshot;+	__le64 flags;+	__le32 refs;+	struct btrfs_disk_key drop_progress;+	u8 drop_level;+	u8 level;+} __attribute__ ((__packed__));++struct btrfs_root_item {+	struct btrfs_inode_item inode;+	__le64 generation;+	__le64 root_dirid;+	__le64 bytenr;+	__le64 byte_limit;+	__le64 bytes_used;+	__le64 last_snapshot;+	__le64 flags;+	__le32 refs;+	struct btrfs_disk_key drop_progress;+	u8 drop_level;+	u8 level;++	/*+	 * The following fields appear after subvol_uuids+subvol_times+	 * were introduced.+	 */++	/*+	 * This generation number is used to test if the new fields are valid+	 * and up to date while reading the root item. Everytime the root item+	 * is written out, the "generation" field is copied into this field. If+	 * anyone ever mounted the fs with an older kernel, we will have+	 * mismatching generation values here and thus must invalidate the+	 * new fields. See btrfs_update_root and btrfs_find_last_root for+	 * details.+	 * the offset of generation_v2 is also used as the start for the memset+	 * when invalidating the fields.+	 */+	__le64 generation_v2;+	u8 uuid[BTRFS_UUID_SIZE];+	u8 parent_uuid[BTRFS_UUID_SIZE];+	u8 received_uuid[BTRFS_UUID_SIZE];+	__le64 ctransid; /* updated when an inode changes */+	__le64 otransid; /* trans when created */+	__le64 stransid; /* trans when sent. non-zero for received subvol */+	__le64 rtransid; /* trans when received. non-zero for received subvol */+	struct btrfs_timespec ctime;+	struct btrfs_timespec otime;+	struct btrfs_timespec stime;+	struct btrfs_timespec rtime;+        __le64 reserved[8]; /* for future */+} __attribute__ ((__packed__));++/*+ * this is used for both forward and backward root refs+ */+struct btrfs_root_ref {+	__le64 dirid;+	__le64 sequence;+	__le16 name_len;+} __attribute__ ((__packed__));++#define BTRFS_FILE_EXTENT_INLINE 0+#define BTRFS_FILE_EXTENT_REG 1+#define BTRFS_FILE_EXTENT_PREALLOC 2++struct btrfs_file_extent_item {+	/*+	 * transaction id that created this extent+	 */+	__le64 generation;+	/*+	 * max number of bytes to hold this extent in ram+	 * when we split a compressed extent we can't know how big+	 * each of the resulting pieces will be.  So, this is+	 * an upper limit on the size of the extent in ram instead of+	 * an exact limit.+	 */+	__le64 ram_bytes;++	/*+	 * 32 bits for the various ways we might encode the data,+	 * including compression and encryption.  If any of these+	 * are set to something a given disk format doesn't understand+	 * it is treated like an incompat flag for reading and writing,+	 * but not for stat.+	 */+	u8 compression;+	u8 encryption;+	__le16 other_encoding; /* spare for later use */++	/* are we inline data or a real extent? */+	u8 type;++	/*+	 * disk space consumed by the extent, checksum blocks are included+	 * in these numbers+	 */+	__le64 disk_bytenr;+	__le64 disk_num_bytes;+	/*+	 * the logical offset in file blocks (no csums)+	 * this extent record is for.  This allows a file extent to point+	 * into the middle of an existing extent on disk, sharing it+	 * between two snapshots (useful if some bytes in the middle of the+	 * extent have changed+	 */+	__le64 offset;+	/*+	 * the logical number of file blocks (no csums included)+	 */+	__le64 num_bytes;++} __attribute__ ((__packed__));++struct btrfs_csum_item {+	u8 csum;+} __attribute__ ((__packed__));++/*+ * We don't want to overwrite 1M at the beginning of device, even though+ * there is our 1st superblock at 64k. Some possible reasons:+ *  - 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)++/* tag for the radix tree of block groups in ram */+#define BTRFS_BLOCK_GROUP_DATA		(1ULL << 0)+#define BTRFS_BLOCK_GROUP_SYSTEM	(1ULL << 1)+#define BTRFS_BLOCK_GROUP_METADATA	(1ULL << 2)+#define BTRFS_BLOCK_GROUP_RAID0		(1ULL << 3)+#define BTRFS_BLOCK_GROUP_RAID1		(1ULL << 4)+#define BTRFS_BLOCK_GROUP_DUP		(1ULL << 5)+#define BTRFS_BLOCK_GROUP_RAID10	(1ULL << 6)+#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_BLOCK_GROUP_TYPE_MASK	(BTRFS_BLOCK_GROUP_DATA |    \+					 BTRFS_BLOCK_GROUP_SYSTEM |  \+					 BTRFS_BLOCK_GROUP_METADATA)++#define BTRFS_BLOCK_GROUP_PROFILE_MASK	(BTRFS_BLOCK_GROUP_RAID0 |   \+					 BTRFS_BLOCK_GROUP_RAID1 |   \+					 BTRFS_BLOCK_GROUP_RAID5 |   \+					 BTRFS_BLOCK_GROUP_RAID6 |   \+					 BTRFS_BLOCK_GROUP_DUP |     \+					 BTRFS_BLOCK_GROUP_RAID10)++/* used in struct btrfs_balance_args fields */+#define BTRFS_AVAIL_ALLOC_BIT_SINGLE	(1ULL << 48)++#define BTRFS_QGROUP_STATUS_OFF			0+#define BTRFS_QGROUP_STATUS_ON			1+#define BTRFS_QGROUP_STATUS_SCANNING		2++#define BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT	(1 << 0)++struct btrfs_qgroup_status_item {+	__le64 version;+	__le64 generation;+	__le64 flags;+	__le64 scan;		/* progress during scanning */+} __attribute__ ((__packed__));++struct btrfs_block_group_item {+	__le64 used;+	__le64 chunk_objectid;+	__le64 flags;+} __attribute__ ((__packed__));++struct btrfs_qgroup_info_item {+	__le64 generation;+	__le64 referenced;+	__le64 referenced_compressed;+	__le64 exclusive;+	__le64 exclusive_compressed;+} __attribute__ ((__packed__));++/* flags definition for qgroup limits */+#define BTRFS_QGROUP_LIMIT_MAX_RFER	(1ULL << 0)+#define BTRFS_QGROUP_LIMIT_MAX_EXCL	(1ULL << 1)+#define BTRFS_QGROUP_LIMIT_RSV_RFER	(1ULL << 2)+#define BTRFS_QGROUP_LIMIT_RSV_EXCL	(1ULL << 3)+#define BTRFS_QGROUP_LIMIT_RFER_CMPR	(1ULL << 4)+#define BTRFS_QGROUP_LIMIT_EXCL_CMPR	(1ULL << 5)++struct btrfs_qgroup_limit_item {+	__le64 flags;+	__le64 max_referenced;+	__le64 max_exclusive;+	__le64 rsv_referenced;+	__le64 rsv_exclusive;+} __attribute__ ((__packed__));++struct btrfs_space_info {+	u64 flags;+	u64 total_bytes;+	u64 bytes_used;+	u64 bytes_pinned;+	int full;+	struct list_head list;+};++struct btrfs_block_group_cache {+	struct cache_extent cache;+	struct btrfs_key key;+	struct btrfs_block_group_item item;+	struct btrfs_space_info *space_info;+	struct btrfs_free_space_ctl *free_space_ctl;+	u64 pinned;+	u64 flags;+	int cached;+	int ro;+};++struct btrfs_extent_ops {+       int (*alloc_extent)(struct btrfs_root *root, u64 num_bytes,+		           u64 hint_byte, struct btrfs_key *ins);+       int (*free_extent)(struct btrfs_root *root, u64 bytenr,+		          u64 num_bytes);+};++struct btrfs_device;+struct btrfs_fs_devices;+struct btrfs_fs_info {+	u8 fsid[BTRFS_FSID_SIZE];+	u8 chunk_tree_uuid[BTRFS_UUID_SIZE];+	struct btrfs_root *fs_root;+	struct btrfs_root *extent_root;+	struct btrfs_root *tree_root;+	struct btrfs_root *chunk_root;+	struct btrfs_root *dev_root;+	struct btrfs_root *csum_root;++	struct rb_root fs_root_tree;++	/* the log root tree is a directory of all the other log roots */+	struct btrfs_root *log_root_tree;++	struct extent_io_tree extent_cache;+	struct extent_io_tree free_space_cache;+	struct extent_io_tree block_group_cache;+	struct extent_io_tree pinned_extents;+	struct extent_io_tree pending_del;+	struct extent_io_tree extent_ins;++	/* logical->physical extent mapping */+	struct btrfs_mapping_tree mapping_tree;++	u64 generation;+	u64 last_trans_committed;++	u64 avail_data_alloc_bits;+	u64 avail_metadata_alloc_bits;+	u64 avail_system_alloc_bits;+	u64 data_alloc_profile;+	u64 metadata_alloc_profile;+	u64 system_alloc_profile;+	u64 alloc_start;++	struct btrfs_trans_handle *running_transaction;+	struct btrfs_super_block *super_copy;+	struct mutex fs_mutex;++	u64 super_bytenr;+	u64 total_pinned;++	struct btrfs_extent_ops *extent_ops;+	struct list_head dirty_cowonly_roots;+	struct list_head recow_ebs;++	struct btrfs_fs_devices *fs_devices;+	struct list_head space_info;+	int system_allocs;++	unsigned int readonly:1;+	unsigned int on_restoring:1;+	unsigned int is_chunk_recover:1;++	int (*free_extent_hook)(struct btrfs_trans_handle *trans,+				struct btrfs_root *root,+				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;+};++/*+ * in ram representation of the tree.  extent_root is used for all allocations+ * and for the extent tree extent_root root.+ */+struct btrfs_root {+	struct extent_buffer *node;+	struct extent_buffer *commit_root;+	struct btrfs_root_item root_item;+	struct btrfs_key root_key;+	struct btrfs_fs_info *fs_info;+	u64 objectid;+	u64 last_trans;++	/* data allocations are done in sectorsize units */+	u32 sectorsize;++	/* node allocations are done in nodesize units */+	u32 nodesize;++	/* leaf allocations are done in leafsize units */+	u32 leafsize;++	/* leaf allocations are done in leafsize units */+	u32 stripesize;++	int ref_cows;+	int track_dirty;+++	u32 type;+	u64 highest_inode;+	u64 last_inode_alloc;++	/* the dirty list is only used by non-reference counted roots */+	struct list_head dirty_list;+	struct rb_node rb_node;+};++/*+ * 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+ * the FS+ */+#define BTRFS_INODE_ITEM_KEY		1+#define BTRFS_INODE_REF_KEY		12+#define BTRFS_INODE_EXTREF_KEY		13+#define BTRFS_XATTR_ITEM_KEY		24+#define BTRFS_ORPHAN_ITEM_KEY		48++#define BTRFS_DIR_LOG_ITEM_KEY  60+#define BTRFS_DIR_LOG_INDEX_KEY 72+/*+ * dir items are the name -> inode pointers in a directory.  There is one+ * for every name in a directory.+ */+#define BTRFS_DIR_ITEM_KEY	84+#define BTRFS_DIR_INDEX_KEY	96++/*+ * extent data is for file data+ */+#define BTRFS_EXTENT_DATA_KEY	108++/*+ * csum items have the checksums for data in the extents+ */+#define BTRFS_CSUM_ITEM_KEY	120+/*+ * extent csums are stored in a separate tree and hold csums for+ * an entire extent on disk.+ */+#define BTRFS_EXTENT_CSUM_KEY	128++/*+ * root items point to tree roots.  There are typically in the root+ * tree used by the super block to find all the other trees+ */+#define BTRFS_ROOT_ITEM_KEY	132++/*+ * root backrefs tie subvols and snapshots to the directory entries that+ * reference them+ */+#define BTRFS_ROOT_BACKREF_KEY	144++/*+ * root refs make a fast index for listing all of the snapshots and+ * subvolumes referenced by a given root.  They point directly to the+ * directory item in the root that references the subvol+ */+#define BTRFS_ROOT_REF_KEY	156++/*+ * extent items are in the extent map tree.  These record which blocks+ * are used, and how many references there are to each block+ */+#define BTRFS_EXTENT_ITEM_KEY	168++/*+ * The same as the BTRFS_EXTENT_ITEM_KEY, except it's metadata we already know+ * the length, so we save the level in key->offset instead of the length.+ */+#define BTRFS_METADATA_ITEM_KEY	169++#define BTRFS_TREE_BLOCK_REF_KEY	176++#define BTRFS_EXTENT_DATA_REF_KEY	178++/* old style extent backrefs */+#define BTRFS_EXTENT_REF_V0_KEY		180++#define BTRFS_SHARED_BLOCK_REF_KEY	182++#define BTRFS_SHARED_DATA_REF_KEY	184+++/*+ * block groups give us hints into the extent allocation trees.  Which+ * blocks are free etc etc+ */+#define BTRFS_BLOCK_GROUP_ITEM_KEY 192++#define BTRFS_DEV_EXTENT_KEY	204+#define BTRFS_DEV_ITEM_KEY	216+#define BTRFS_CHUNK_ITEM_KEY	228++#define BTRFS_BALANCE_ITEM_KEY	248++/*+ * quota groups+ */+#define BTRFS_QGROUP_STATUS_KEY		240+#define BTRFS_QGROUP_INFO_KEY		242+#define BTRFS_QGROUP_LIMIT_KEY		244+#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).+ */+#define BTRFS_DEV_STATS_KEY	249++/*+ * Persistently stores the device replace state in the device tree.+ * The key is built like this: (0, BTRFS_DEV_REPLACE_KEY, 0).+ */+#define BTRFS_DEV_REPLACE_KEY	250++/*+ * Stores items that allow to quickly map UUIDs to something else.+ * These items are part of the filesystem UUID tree.+ * The key is built like this:+ * (UUID_upper_64_bits, BTRFS_UUID_KEY*, UUID_lower_64_bits).+ */+#if BTRFS_UUID_SIZE != 16+#error "UUID items require BTRFS_UUID_SIZE == 16!"+#endif+#define BTRFS_UUID_KEY_SUBVOL	251	/* for UUIDs assigned to subvols */+#define BTRFS_UUID_KEY_RECEIVED_SUBVOL	252	/* for UUIDs assigned to+						 * received subvols */++/*+ * string items are for debugging.  They just store a short string of+ * data in the FS+ */+#define BTRFS_STRING_ITEM_KEY	253+/*+ * Inode flags+ */+#define BTRFS_INODE_NODATASUM		(1 << 0)+#define BTRFS_INODE_NODATACOW		(1 << 1)+#define BTRFS_INODE_READONLY		(1 << 2)++#define read_eb_member(eb, ptr, type, member, result) (			\+	read_extent_buffer(eb, (char *)(result),			\+			   ((unsigned long)(ptr)) +			\+			    offsetof(type, member),			\+			   sizeof(((type *)0)->member)))++#define write_eb_member(eb, ptr, type, member, result) (		\+	write_extent_buffer(eb, (char *)(result),			\+			   ((unsigned long)(ptr)) +			\+			    offsetof(type, member),			\+			   sizeof(((type *)0)->member)))++#define BTRFS_SETGET_HEADER_FUNCS(name, type, member, bits)		\+static inline u##bits btrfs_##name(const struct extent_buffer *eb)	\+{									\+	const struct btrfs_header *h = (struct btrfs_header *)eb->data;	\+	return le##bits##_to_cpu(h->member);				\+}									\+static inline void btrfs_set_##name(struct extent_buffer *eb,		\+				    u##bits val)			\+{									\+	struct btrfs_header *h = (struct btrfs_header *)eb->data;	\+	h->member = cpu_to_le##bits(val);				\+}++#define BTRFS_SETGET_FUNCS(name, type, member, bits)			\+static inline u##bits btrfs_##name(const struct extent_buffer *eb,	\+				   const type *s)			\+{									\+	unsigned long offset = (unsigned long)s;			\+	const type *p = (type *) (eb->data + offset);			\+	return get_unaligned_le##bits(&p->member);			\+}									\+static inline void btrfs_set_##name(struct extent_buffer *eb,		\+				    type *s, u##bits val)		\+{									\+	unsigned long offset = (unsigned long)s;			\+	type *p = (type *) (eb->data + offset);				\+	put_unaligned_le##bits(val, &p->member);			\+}++#define BTRFS_SETGET_STACK_FUNCS(name, type, member, bits)		\+static inline u##bits btrfs_##name(const type *s)			\+{									\+	return le##bits##_to_cpu(s->member);				\+}									\+static inline void btrfs_set_##name(type *s, u##bits val)		\+{									\+	s->member = cpu_to_le##bits(val);				\+}++BTRFS_SETGET_FUNCS(device_type, struct btrfs_dev_item, type, 64);+BTRFS_SETGET_FUNCS(device_total_bytes, struct btrfs_dev_item, total_bytes, 64);+BTRFS_SETGET_FUNCS(device_bytes_used, struct btrfs_dev_item, bytes_used, 64);+BTRFS_SETGET_FUNCS(device_io_align, struct btrfs_dev_item, io_align, 32);+BTRFS_SETGET_FUNCS(device_io_width, struct btrfs_dev_item, io_width, 32);+BTRFS_SETGET_FUNCS(device_start_offset, struct btrfs_dev_item,+		   start_offset, 64);+BTRFS_SETGET_FUNCS(device_sector_size, struct btrfs_dev_item, sector_size, 32);+BTRFS_SETGET_FUNCS(device_id, struct btrfs_dev_item, devid, 64);+BTRFS_SETGET_FUNCS(device_group, struct btrfs_dev_item, dev_group, 32);+BTRFS_SETGET_FUNCS(device_seek_speed, struct btrfs_dev_item, seek_speed, 8);+BTRFS_SETGET_FUNCS(device_bandwidth, struct btrfs_dev_item, bandwidth, 8);+BTRFS_SETGET_FUNCS(device_generation, struct btrfs_dev_item, generation, 64);++BTRFS_SETGET_STACK_FUNCS(stack_device_type, struct btrfs_dev_item, type, 64);+BTRFS_SETGET_STACK_FUNCS(stack_device_total_bytes, struct btrfs_dev_item,+			 total_bytes, 64);+BTRFS_SETGET_STACK_FUNCS(stack_device_bytes_used, struct btrfs_dev_item,+			 bytes_used, 64);+BTRFS_SETGET_STACK_FUNCS(stack_device_io_align, struct btrfs_dev_item,+			 io_align, 32);+BTRFS_SETGET_STACK_FUNCS(stack_device_io_width, struct btrfs_dev_item,+			 io_width, 32);+BTRFS_SETGET_STACK_FUNCS(stack_device_sector_size, struct btrfs_dev_item,+			 sector_size, 32);+BTRFS_SETGET_STACK_FUNCS(stack_device_id, struct btrfs_dev_item, devid, 64);+BTRFS_SETGET_STACK_FUNCS(stack_device_group, struct btrfs_dev_item,+			 dev_group, 32);+BTRFS_SETGET_STACK_FUNCS(stack_device_seek_speed, struct btrfs_dev_item,+			 seek_speed, 8);+BTRFS_SETGET_STACK_FUNCS(stack_device_bandwidth, struct btrfs_dev_item,+			 bandwidth, 8);+BTRFS_SETGET_STACK_FUNCS(stack_device_generation, struct btrfs_dev_item,+			 generation, 64);++static inline char *btrfs_device_uuid(struct btrfs_dev_item *d)+{+	return (char *)d + offsetof(struct btrfs_dev_item, uuid);+}++static inline char *btrfs_device_fsid(struct btrfs_dev_item *d)+{+	return (char *)d + offsetof(struct btrfs_dev_item, fsid);+}++BTRFS_SETGET_FUNCS(chunk_length, struct btrfs_chunk, length, 64);+BTRFS_SETGET_FUNCS(chunk_owner, struct btrfs_chunk, owner, 64);+BTRFS_SETGET_FUNCS(chunk_stripe_len, struct btrfs_chunk, stripe_len, 64);+BTRFS_SETGET_FUNCS(chunk_io_align, struct btrfs_chunk, io_align, 32);+BTRFS_SETGET_FUNCS(chunk_io_width, struct btrfs_chunk, io_width, 32);+BTRFS_SETGET_FUNCS(chunk_sector_size, struct btrfs_chunk, sector_size, 32);+BTRFS_SETGET_FUNCS(chunk_type, struct btrfs_chunk, type, 64);+BTRFS_SETGET_FUNCS(chunk_num_stripes, struct btrfs_chunk, num_stripes, 16);+BTRFS_SETGET_FUNCS(chunk_sub_stripes, struct btrfs_chunk, sub_stripes, 16);+BTRFS_SETGET_FUNCS(stripe_devid, struct btrfs_stripe, devid, 64);+BTRFS_SETGET_FUNCS(stripe_offset, struct btrfs_stripe, offset, 64);++static inline char *btrfs_stripe_dev_uuid(struct btrfs_stripe *s)+{+	return (char *)s + offsetof(struct btrfs_stripe, dev_uuid);+}++BTRFS_SETGET_STACK_FUNCS(stack_chunk_length, struct btrfs_chunk, length, 64);+BTRFS_SETGET_STACK_FUNCS(stack_chunk_owner, struct btrfs_chunk, owner, 64);+BTRFS_SETGET_STACK_FUNCS(stack_chunk_stripe_len, struct btrfs_chunk,+			 stripe_len, 64);+BTRFS_SETGET_STACK_FUNCS(stack_chunk_io_align, struct btrfs_chunk,+			 io_align, 32);+BTRFS_SETGET_STACK_FUNCS(stack_chunk_io_width, struct btrfs_chunk,+			 io_width, 32);+BTRFS_SETGET_STACK_FUNCS(stack_chunk_sector_size, struct btrfs_chunk,+			 sector_size, 32);+BTRFS_SETGET_STACK_FUNCS(stack_chunk_type, struct btrfs_chunk, type, 64);+BTRFS_SETGET_STACK_FUNCS(stack_chunk_num_stripes, struct btrfs_chunk,+			 num_stripes, 16);+BTRFS_SETGET_STACK_FUNCS(stack_chunk_sub_stripes, struct btrfs_chunk,+			 sub_stripes, 16);+BTRFS_SETGET_STACK_FUNCS(stack_stripe_devid, struct btrfs_stripe, devid, 64);+BTRFS_SETGET_STACK_FUNCS(stack_stripe_offset, struct btrfs_stripe, offset, 64);++static inline struct btrfs_stripe *btrfs_stripe_nr(struct btrfs_chunk *c,+						   int nr)+{+	unsigned long offset = (unsigned long)c;+	offset += offsetof(struct btrfs_chunk, stripe);+	offset += nr * sizeof(struct btrfs_stripe);+	return (struct btrfs_stripe *)offset;+}++static inline char *btrfs_stripe_dev_uuid_nr(struct btrfs_chunk *c, int nr)+{+	return btrfs_stripe_dev_uuid(btrfs_stripe_nr(c, nr));+}++static inline u64 btrfs_stripe_offset_nr(struct extent_buffer *eb,+					 struct btrfs_chunk *c, int nr)+{+	return btrfs_stripe_offset(eb, btrfs_stripe_nr(c, nr));+}++static inline void btrfs_set_stripe_offset_nr(struct extent_buffer *eb,+					     struct btrfs_chunk *c, int nr,+					     u64 val)+{+	btrfs_set_stripe_offset(eb, btrfs_stripe_nr(c, nr), val);+}++static inline u64 btrfs_stripe_devid_nr(struct extent_buffer *eb,+					 struct btrfs_chunk *c, int nr)+{+	return btrfs_stripe_devid(eb, btrfs_stripe_nr(c, nr));+}++static inline void btrfs_set_stripe_devid_nr(struct extent_buffer *eb,+					     struct btrfs_chunk *c, int nr,+					     u64 val)+{+	btrfs_set_stripe_devid(eb, btrfs_stripe_nr(c, nr), val);+}++/* struct btrfs_block_group_item */+BTRFS_SETGET_STACK_FUNCS(block_group_used, struct btrfs_block_group_item,+			 used, 64);+BTRFS_SETGET_FUNCS(disk_block_group_used, struct btrfs_block_group_item,+			 used, 64);+BTRFS_SETGET_STACK_FUNCS(block_group_chunk_objectid,+			struct btrfs_block_group_item, chunk_objectid, 64);++BTRFS_SETGET_FUNCS(disk_block_group_chunk_objectid,+		   struct btrfs_block_group_item, chunk_objectid, 64);+BTRFS_SETGET_FUNCS(disk_block_group_flags,+		   struct btrfs_block_group_item, flags, 64);+BTRFS_SETGET_STACK_FUNCS(block_group_flags,+			struct btrfs_block_group_item, flags, 64);++/* struct btrfs_inode_ref */+BTRFS_SETGET_FUNCS(inode_ref_name_len, struct btrfs_inode_ref, name_len, 16);+BTRFS_SETGET_STACK_FUNCS(stack_inode_ref_name_len, struct btrfs_inode_ref, name_len, 16);+BTRFS_SETGET_FUNCS(inode_ref_index, struct btrfs_inode_ref, index, 64);++/* struct btrfs_inode_extref */+BTRFS_SETGET_FUNCS(inode_extref_parent, struct btrfs_inode_extref,+		   parent_objectid, 64);+BTRFS_SETGET_FUNCS(inode_extref_name_len, struct btrfs_inode_extref,+		   name_len, 16);+BTRFS_SETGET_FUNCS(inode_extref_index, struct btrfs_inode_extref, index, 64);++/* struct btrfs_inode_item */+BTRFS_SETGET_FUNCS(inode_generation, struct btrfs_inode_item, generation, 64);+BTRFS_SETGET_FUNCS(inode_sequence, struct btrfs_inode_item, sequence, 64);+BTRFS_SETGET_FUNCS(inode_transid, struct btrfs_inode_item, transid, 64);+BTRFS_SETGET_FUNCS(inode_size, struct btrfs_inode_item, size, 64);+BTRFS_SETGET_FUNCS(inode_nbytes, struct btrfs_inode_item, nbytes, 64);+BTRFS_SETGET_FUNCS(inode_block_group, struct btrfs_inode_item, block_group, 64);+BTRFS_SETGET_FUNCS(inode_nlink, struct btrfs_inode_item, nlink, 32);+BTRFS_SETGET_FUNCS(inode_uid, struct btrfs_inode_item, uid, 32);+BTRFS_SETGET_FUNCS(inode_gid, struct btrfs_inode_item, gid, 32);+BTRFS_SETGET_FUNCS(inode_mode, struct btrfs_inode_item, mode, 32);+BTRFS_SETGET_FUNCS(inode_rdev, struct btrfs_inode_item, rdev, 64);+BTRFS_SETGET_FUNCS(inode_flags, struct btrfs_inode_item, flags, 64);++BTRFS_SETGET_STACK_FUNCS(stack_inode_generation,+			 struct btrfs_inode_item, generation, 64);+BTRFS_SETGET_STACK_FUNCS(stack_inode_sequence,+			 struct btrfs_inode_item, generation, 64);+BTRFS_SETGET_STACK_FUNCS(stack_inode_size,+			 struct btrfs_inode_item, size, 64);+BTRFS_SETGET_STACK_FUNCS(stack_inode_nbytes,+			 struct btrfs_inode_item, nbytes, 64);+BTRFS_SETGET_STACK_FUNCS(stack_inode_block_group,+			 struct btrfs_inode_item, block_group, 64);+BTRFS_SETGET_STACK_FUNCS(stack_inode_nlink,+			 struct btrfs_inode_item, nlink, 32);+BTRFS_SETGET_STACK_FUNCS(stack_inode_uid,+			 struct btrfs_inode_item, uid, 32);+BTRFS_SETGET_STACK_FUNCS(stack_inode_gid,+			 struct btrfs_inode_item, gid, 32);+BTRFS_SETGET_STACK_FUNCS(stack_inode_mode,+			 struct btrfs_inode_item, mode, 32);+BTRFS_SETGET_STACK_FUNCS(stack_inode_rdev,+			 struct btrfs_inode_item, rdev, 64);+BTRFS_SETGET_STACK_FUNCS(stack_inode_flags,+			 struct btrfs_inode_item, flags, 64);++static inline struct btrfs_timespec *+btrfs_inode_atime(struct btrfs_inode_item *inode_item)+{+	unsigned long ptr = (unsigned long)inode_item;+	ptr += offsetof(struct btrfs_inode_item, atime);+	return (struct btrfs_timespec *)ptr;+}++static inline struct btrfs_timespec *+btrfs_inode_mtime(struct btrfs_inode_item *inode_item)+{+	unsigned long ptr = (unsigned long)inode_item;+	ptr += offsetof(struct btrfs_inode_item, mtime);+	return (struct btrfs_timespec *)ptr;+}++static inline struct btrfs_timespec *+btrfs_inode_ctime(struct btrfs_inode_item *inode_item)+{+	unsigned long ptr = (unsigned long)inode_item;+	ptr += offsetof(struct btrfs_inode_item, ctime);+	return (struct btrfs_timespec *)ptr;+}++static inline struct btrfs_timespec *+btrfs_inode_otime(struct btrfs_inode_item *inode_item)+{+	unsigned long ptr = (unsigned long)inode_item;+	ptr += offsetof(struct btrfs_inode_item, otime);+	return (struct btrfs_timespec *)ptr;+}++BTRFS_SETGET_FUNCS(timespec_sec, struct btrfs_timespec, sec, 64);+BTRFS_SETGET_FUNCS(timespec_nsec, struct btrfs_timespec, nsec, 32);+BTRFS_SETGET_STACK_FUNCS(stack_timespec_sec, struct btrfs_timespec,+			 sec, 64);+BTRFS_SETGET_STACK_FUNCS(stack_timespec_nsec, struct btrfs_timespec,+			 nsec, 32);++/* struct btrfs_dev_extent */+BTRFS_SETGET_FUNCS(dev_extent_chunk_tree, struct btrfs_dev_extent,+		   chunk_tree, 64);+BTRFS_SETGET_FUNCS(dev_extent_chunk_objectid, struct btrfs_dev_extent,+		   chunk_objectid, 64);+BTRFS_SETGET_FUNCS(dev_extent_chunk_offset, struct btrfs_dev_extent,+		   chunk_offset, 64);+BTRFS_SETGET_FUNCS(dev_extent_length, struct btrfs_dev_extent, length, 64);++static inline u8 *btrfs_dev_extent_chunk_tree_uuid(struct btrfs_dev_extent *dev)+{+	unsigned long ptr = offsetof(struct btrfs_dev_extent, chunk_tree_uuid);+	return (u8 *)((unsigned long)dev + ptr);+}+++/* struct btrfs_extent_item */+BTRFS_SETGET_FUNCS(extent_refs, struct btrfs_extent_item, refs, 64);+BTRFS_SETGET_STACK_FUNCS(stack_extent_refs, struct btrfs_extent_item, refs, 64);+BTRFS_SETGET_FUNCS(extent_generation, struct btrfs_extent_item,+		   generation, 64);+BTRFS_SETGET_FUNCS(extent_flags, struct btrfs_extent_item, flags, 64);+BTRFS_SETGET_STACK_FUNCS(stack_extent_flags, struct btrfs_extent_item, flags, 64);++BTRFS_SETGET_FUNCS(extent_refs_v0, struct btrfs_extent_item_v0, refs, 32);++BTRFS_SETGET_FUNCS(tree_block_level, struct btrfs_tree_block_info, level, 8);++static inline void btrfs_tree_block_key(struct extent_buffer *eb,+					struct btrfs_tree_block_info *item,+					struct btrfs_disk_key *key)+{+	read_eb_member(eb, item, struct btrfs_tree_block_info, key, key);+}++static inline void btrfs_set_tree_block_key(struct extent_buffer *eb,+					    struct btrfs_tree_block_info *item,+					    struct btrfs_disk_key *key)+{+	write_eb_member(eb, item, struct btrfs_tree_block_info, key, key);+}++BTRFS_SETGET_FUNCS(extent_data_ref_root, struct btrfs_extent_data_ref,+		   root, 64);+BTRFS_SETGET_FUNCS(extent_data_ref_objectid, struct btrfs_extent_data_ref,+		   objectid, 64);+BTRFS_SETGET_FUNCS(extent_data_ref_offset, struct btrfs_extent_data_ref,+		   offset, 64);+BTRFS_SETGET_FUNCS(extent_data_ref_count, struct btrfs_extent_data_ref,+		   count, 32);++BTRFS_SETGET_FUNCS(shared_data_ref_count, struct btrfs_shared_data_ref,+		   count, 32);++BTRFS_SETGET_FUNCS(extent_inline_ref_type, struct btrfs_extent_inline_ref,+		   type, 8);+BTRFS_SETGET_FUNCS(extent_inline_ref_offset, struct btrfs_extent_inline_ref,+		   offset, 64);+BTRFS_SETGET_STACK_FUNCS(stack_extent_inline_ref_type,+			 struct btrfs_extent_inline_ref, type, 8);+BTRFS_SETGET_STACK_FUNCS(stack_extent_inline_ref_offset,+			 struct btrfs_extent_inline_ref, offset, 64);++static inline u32 btrfs_extent_inline_ref_size(int type)+{+	if (type == BTRFS_TREE_BLOCK_REF_KEY ||+	    type == BTRFS_SHARED_BLOCK_REF_KEY)+		return sizeof(struct btrfs_extent_inline_ref);+	if (type == BTRFS_SHARED_DATA_REF_KEY)+		return sizeof(struct btrfs_shared_data_ref) ++		       sizeof(struct btrfs_extent_inline_ref);+	if (type == BTRFS_EXTENT_DATA_REF_KEY)+		return sizeof(struct btrfs_extent_data_ref) ++		       offsetof(struct btrfs_extent_inline_ref, offset);+	BUG();+	return 0;+}++BTRFS_SETGET_FUNCS(ref_root_v0, struct btrfs_extent_ref_v0, root, 64);+BTRFS_SETGET_FUNCS(ref_generation_v0, struct btrfs_extent_ref_v0,+		   generation, 64);+BTRFS_SETGET_FUNCS(ref_objectid_v0, struct btrfs_extent_ref_v0, objectid, 64);+BTRFS_SETGET_FUNCS(ref_count_v0, struct btrfs_extent_ref_v0, count, 32);++/* struct btrfs_node */+BTRFS_SETGET_FUNCS(key_blockptr, struct btrfs_key_ptr, blockptr, 64);+BTRFS_SETGET_FUNCS(key_generation, struct btrfs_key_ptr, generation, 64);++static inline u64 btrfs_node_blockptr(struct extent_buffer *eb, int nr)+{+	unsigned long ptr;+	ptr = offsetof(struct btrfs_node, ptrs) ++		sizeof(struct btrfs_key_ptr) * nr;+	return btrfs_key_blockptr(eb, (struct btrfs_key_ptr *)ptr);+}++static inline void btrfs_set_node_blockptr(struct extent_buffer *eb,+					   int nr, u64 val)+{+	unsigned long ptr;+	ptr = offsetof(struct btrfs_node, ptrs) ++		sizeof(struct btrfs_key_ptr) * nr;+	btrfs_set_key_blockptr(eb, (struct btrfs_key_ptr *)ptr, val);+}++static inline u64 btrfs_node_ptr_generation(struct extent_buffer *eb, int nr)+{+	unsigned long ptr;+	ptr = offsetof(struct btrfs_node, ptrs) ++		sizeof(struct btrfs_key_ptr) * nr;+	return btrfs_key_generation(eb, (struct btrfs_key_ptr *)ptr);+}++static inline void btrfs_set_node_ptr_generation(struct extent_buffer *eb,+						 int nr, u64 val)+{+	unsigned long ptr;+	ptr = offsetof(struct btrfs_node, ptrs) ++		sizeof(struct btrfs_key_ptr) * nr;+	btrfs_set_key_generation(eb, (struct btrfs_key_ptr *)ptr, val);+}++static inline unsigned long btrfs_node_key_ptr_offset(int nr)+{+	return offsetof(struct btrfs_node, ptrs) ++		sizeof(struct btrfs_key_ptr) * nr;+}++static inline void btrfs_node_key(struct extent_buffer *eb,+				  struct btrfs_disk_key *disk_key, int nr)+{+	unsigned long ptr;+	ptr = btrfs_node_key_ptr_offset(nr);+	read_eb_member(eb, (struct btrfs_key_ptr *)ptr,+		       struct btrfs_key_ptr, key, disk_key);+}++static inline void btrfs_set_node_key(struct extent_buffer *eb,+				      struct btrfs_disk_key *disk_key, int nr)+{+	unsigned long ptr;+	ptr = btrfs_node_key_ptr_offset(nr);+	write_eb_member(eb, (struct btrfs_key_ptr *)ptr,+		       struct btrfs_key_ptr, key, disk_key);+}++/* struct btrfs_item */+BTRFS_SETGET_FUNCS(item_offset, struct btrfs_item, offset, 32);+BTRFS_SETGET_FUNCS(item_size, struct btrfs_item, size, 32);++static inline unsigned long btrfs_item_nr_offset(int nr)+{+	return offsetof(struct btrfs_leaf, items) ++		sizeof(struct btrfs_item) * nr;+}++static inline struct btrfs_item *btrfs_item_nr(int nr)+{+	return (struct btrfs_item *)btrfs_item_nr_offset(nr);+}++static inline u32 btrfs_item_end(struct extent_buffer *eb,+				 struct btrfs_item *item)+{+	return btrfs_item_offset(eb, item) + btrfs_item_size(eb, item);+}++static inline u32 btrfs_item_end_nr(struct extent_buffer *eb, int nr)+{+	return btrfs_item_end(eb, btrfs_item_nr(nr));+}++static inline u32 btrfs_item_offset_nr(struct extent_buffer *eb, int nr)+{+	return btrfs_item_offset(eb, btrfs_item_nr(nr));+}++static inline u32 btrfs_item_size_nr(struct extent_buffer *eb, int nr)+{+	return btrfs_item_size(eb, btrfs_item_nr(nr));+}++static inline void btrfs_item_key(struct extent_buffer *eb,+			   struct btrfs_disk_key *disk_key, int nr)+{+	struct btrfs_item *item = btrfs_item_nr(nr);+	read_eb_member(eb, item, struct btrfs_item, key, disk_key);+}++static inline void btrfs_set_item_key(struct extent_buffer *eb,+			       struct btrfs_disk_key *disk_key, int nr)+{+	struct btrfs_item *item = btrfs_item_nr(nr);+	write_eb_member(eb, item, struct btrfs_item, key, disk_key);+}++BTRFS_SETGET_FUNCS(dir_log_end, struct btrfs_dir_log_item, end, 64);++/*+ * struct btrfs_root_ref+ */+BTRFS_SETGET_FUNCS(root_ref_dirid, struct btrfs_root_ref, dirid, 64);+BTRFS_SETGET_FUNCS(root_ref_sequence, struct btrfs_root_ref, sequence, 64);+BTRFS_SETGET_FUNCS(root_ref_name_len, struct btrfs_root_ref, name_len, 16);++BTRFS_SETGET_STACK_FUNCS(stack_root_ref_dirid, struct btrfs_root_ref, dirid, 64);+BTRFS_SETGET_STACK_FUNCS(stack_root_ref_sequence, struct btrfs_root_ref, sequence, 64);+BTRFS_SETGET_STACK_FUNCS(stack_root_ref_name_len, struct btrfs_root_ref, name_len, 16);++/* struct btrfs_dir_item */+BTRFS_SETGET_FUNCS(dir_data_len, struct btrfs_dir_item, data_len, 16);+BTRFS_SETGET_FUNCS(dir_type, struct btrfs_dir_item, type, 8);+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_name_len, struct btrfs_dir_item, name_len, 16);++static inline void btrfs_dir_item_key(struct extent_buffer *eb,+				      struct btrfs_dir_item *item,+				      struct btrfs_disk_key *key)+{+	read_eb_member(eb, item, struct btrfs_dir_item, location, key);+}++static inline void btrfs_set_dir_item_key(struct extent_buffer *eb,+					  struct btrfs_dir_item *item,+					  struct btrfs_disk_key *key)+{+	write_eb_member(eb, item, struct btrfs_dir_item, location, key);+}++/* struct btrfs_free_space_header */+BTRFS_SETGET_FUNCS(free_space_entries, struct btrfs_free_space_header,+		   num_entries, 64);+BTRFS_SETGET_FUNCS(free_space_bitmaps, struct btrfs_free_space_header,+		   num_bitmaps, 64);+BTRFS_SETGET_FUNCS(free_space_generation, struct btrfs_free_space_header,+		   generation, 64);++static inline void btrfs_free_space_key(struct extent_buffer *eb,+					struct btrfs_free_space_header *h,+					struct btrfs_disk_key *key)+{+	read_eb_member(eb, h, struct btrfs_free_space_header, location, key);+}++static inline void btrfs_set_free_space_key(struct extent_buffer *eb,+					    struct btrfs_free_space_header *h,+					    struct btrfs_disk_key *key)+{+	write_eb_member(eb, h, struct btrfs_free_space_header, location, key);+}++/* struct btrfs_disk_key */+BTRFS_SETGET_STACK_FUNCS(disk_key_objectid, struct btrfs_disk_key,+			 objectid, 64);+BTRFS_SETGET_STACK_FUNCS(disk_key_offset, struct btrfs_disk_key, offset, 64);+BTRFS_SETGET_STACK_FUNCS(disk_key_type, struct btrfs_disk_key, type, 8);++static inline void btrfs_disk_key_to_cpu(struct btrfs_key *cpu,+					 struct btrfs_disk_key *disk)+{+	cpu->offset = le64_to_cpu(disk->offset);+	cpu->type = disk->type;+	cpu->objectid = le64_to_cpu(disk->objectid);+}++static inline void btrfs_cpu_key_to_disk(struct btrfs_disk_key *disk,+					 struct btrfs_key *cpu)+{+	disk->offset = cpu_to_le64(cpu->offset);+	disk->type = cpu->type;+	disk->objectid = cpu_to_le64(cpu->objectid);+}++static inline void btrfs_node_key_to_cpu(struct extent_buffer *eb,+				  struct btrfs_key *key, int nr)+{+	struct btrfs_disk_key disk_key;+	btrfs_node_key(eb, &disk_key, nr);+	btrfs_disk_key_to_cpu(key, &disk_key);+}++static inline void btrfs_item_key_to_cpu(struct extent_buffer *eb,+				  struct btrfs_key *key, int nr)+{+	struct btrfs_disk_key disk_key;+	btrfs_item_key(eb, &disk_key, nr);+	btrfs_disk_key_to_cpu(key, &disk_key);+}++static inline void btrfs_dir_item_key_to_cpu(struct extent_buffer *eb,+				      struct btrfs_dir_item *item,+				      struct btrfs_key *key)+{+	struct btrfs_disk_key disk_key;+	btrfs_dir_item_key(eb, item, &disk_key);+	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,+			  generation, 64);+BTRFS_SETGET_HEADER_FUNCS(header_owner, struct btrfs_header, owner, 64);+BTRFS_SETGET_HEADER_FUNCS(header_nritems, struct btrfs_header, nritems, 32);+BTRFS_SETGET_HEADER_FUNCS(header_flags, struct btrfs_header, flags, 64);+BTRFS_SETGET_HEADER_FUNCS(header_level, struct btrfs_header, level, 8);+BTRFS_SETGET_STACK_FUNCS(stack_header_bytenr, struct btrfs_header, bytenr, 64);+BTRFS_SETGET_STACK_FUNCS(stack_header_nritems, struct btrfs_header, nritems,+			 32);+BTRFS_SETGET_STACK_FUNCS(stack_header_owner, struct btrfs_header, owner, 64);+BTRFS_SETGET_STACK_FUNCS(stack_header_generation, struct btrfs_header,+			 generation, 64);++static inline int btrfs_header_flag(struct extent_buffer *eb, u64 flag)+{+	return (btrfs_header_flags(eb) & flag) == flag;+}++static inline int btrfs_set_header_flag(struct extent_buffer *eb, u64 flag)+{+	u64 flags = btrfs_header_flags(eb);+	btrfs_set_header_flags(eb, flags | flag);+	return (flags & flag) == flag;+}++static inline int btrfs_clear_header_flag(struct extent_buffer *eb, u64 flag)+{+	u64 flags = btrfs_header_flags(eb);+	btrfs_set_header_flags(eb, flags & ~flag);+	return (flags & flag) == flag;+}++static inline int btrfs_header_backref_rev(struct extent_buffer *eb)+{+	u64 flags = btrfs_header_flags(eb);+	return flags >> BTRFS_BACKREF_REV_SHIFT;+}++static inline void btrfs_set_header_backref_rev(struct extent_buffer *eb,+						int rev)+{+	u64 flags = btrfs_header_flags(eb);+	flags &= ~BTRFS_BACKREF_REV_MASK;+	flags |= (u64)rev << BTRFS_BACKREF_REV_SHIFT;+	btrfs_set_header_flags(eb, flags);+}++static inline unsigned long btrfs_header_fsid(void)+{+	return offsetof(struct btrfs_header, fsid);+}++static inline unsigned long btrfs_header_chunk_tree_uuid(struct extent_buffer *eb)+{+	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);+}++/* struct btrfs_root_item */+BTRFS_SETGET_FUNCS(disk_root_generation, struct btrfs_root_item,+		   generation, 64);+BTRFS_SETGET_FUNCS(disk_root_refs, struct btrfs_root_item, refs, 32);+BTRFS_SETGET_FUNCS(disk_root_bytenr, struct btrfs_root_item, bytenr, 64);+BTRFS_SETGET_FUNCS(disk_root_level, struct btrfs_root_item, level, 8);++BTRFS_SETGET_STACK_FUNCS(root_generation, struct btrfs_root_item,+			 generation, 64);+BTRFS_SETGET_STACK_FUNCS(root_bytenr, struct btrfs_root_item, bytenr, 64);+BTRFS_SETGET_STACK_FUNCS(root_level, struct btrfs_root_item, level, 8);+BTRFS_SETGET_STACK_FUNCS(root_dirid, struct btrfs_root_item, root_dirid, 64);+BTRFS_SETGET_STACK_FUNCS(root_refs, struct btrfs_root_item, refs, 32);+BTRFS_SETGET_STACK_FUNCS(root_flags, struct btrfs_root_item, flags, 64);+BTRFS_SETGET_STACK_FUNCS(root_used, struct btrfs_root_item, bytes_used, 64);+BTRFS_SETGET_STACK_FUNCS(root_limit, struct btrfs_root_item, byte_limit, 64);+BTRFS_SETGET_STACK_FUNCS(root_last_snapshot, struct btrfs_root_item,+			 last_snapshot, 64);+BTRFS_SETGET_STACK_FUNCS(root_generation_v2, struct btrfs_root_item,+			 generation_v2, 64);+BTRFS_SETGET_STACK_FUNCS(root_ctransid, struct btrfs_root_item,+			 ctransid, 64);+BTRFS_SETGET_STACK_FUNCS(root_otransid, struct btrfs_root_item,+			 otransid, 64);+BTRFS_SETGET_STACK_FUNCS(root_stransid, struct btrfs_root_item,+			 stransid, 64);+BTRFS_SETGET_STACK_FUNCS(root_rtransid, struct btrfs_root_item,+			 rtransid, 64);++/* struct btrfs_root_backup */+BTRFS_SETGET_STACK_FUNCS(backup_tree_root, struct btrfs_root_backup,+		   tree_root, 64);+BTRFS_SETGET_STACK_FUNCS(backup_tree_root_gen, struct btrfs_root_backup,+		   tree_root_gen, 64);+BTRFS_SETGET_STACK_FUNCS(backup_tree_root_level, struct btrfs_root_backup,+		   tree_root_level, 8);++BTRFS_SETGET_STACK_FUNCS(backup_chunk_root, struct btrfs_root_backup,+		   chunk_root, 64);+BTRFS_SETGET_STACK_FUNCS(backup_chunk_root_gen, struct btrfs_root_backup,+		   chunk_root_gen, 64);+BTRFS_SETGET_STACK_FUNCS(backup_chunk_root_level, struct btrfs_root_backup,+		   chunk_root_level, 8);++BTRFS_SETGET_STACK_FUNCS(backup_extent_root, struct btrfs_root_backup,+		   extent_root, 64);+BTRFS_SETGET_STACK_FUNCS(backup_extent_root_gen, struct btrfs_root_backup,+		   extent_root_gen, 64);+BTRFS_SETGET_STACK_FUNCS(backup_extent_root_level, struct btrfs_root_backup,+		   extent_root_level, 8);++BTRFS_SETGET_STACK_FUNCS(backup_fs_root, struct btrfs_root_backup,+		   fs_root, 64);+BTRFS_SETGET_STACK_FUNCS(backup_fs_root_gen, struct btrfs_root_backup,+		   fs_root_gen, 64);+BTRFS_SETGET_STACK_FUNCS(backup_fs_root_level, struct btrfs_root_backup,+		   fs_root_level, 8);++BTRFS_SETGET_STACK_FUNCS(backup_dev_root, struct btrfs_root_backup,+		   dev_root, 64);+BTRFS_SETGET_STACK_FUNCS(backup_dev_root_gen, struct btrfs_root_backup,+		   dev_root_gen, 64);+BTRFS_SETGET_STACK_FUNCS(backup_dev_root_level, struct btrfs_root_backup,+		   dev_root_level, 8);++BTRFS_SETGET_STACK_FUNCS(backup_csum_root, struct btrfs_root_backup,+		   csum_root, 64);+BTRFS_SETGET_STACK_FUNCS(backup_csum_root_gen, struct btrfs_root_backup,+		   csum_root_gen, 64);+BTRFS_SETGET_STACK_FUNCS(backup_csum_root_level, struct btrfs_root_backup,+		   csum_root_level, 8);+BTRFS_SETGET_STACK_FUNCS(backup_total_bytes, struct btrfs_root_backup,+		   total_bytes, 64);+BTRFS_SETGET_STACK_FUNCS(backup_bytes_used, struct btrfs_root_backup,+		   bytes_used, 64);+BTRFS_SETGET_STACK_FUNCS(backup_num_devices, struct btrfs_root_backup,+		   num_devices, 64);++/* struct btrfs_super_block */++BTRFS_SETGET_STACK_FUNCS(super_bytenr, struct btrfs_super_block, bytenr, 64);+BTRFS_SETGET_STACK_FUNCS(super_flags, struct btrfs_super_block, flags, 64);+BTRFS_SETGET_STACK_FUNCS(super_generation, struct btrfs_super_block,+			 generation, 64);+BTRFS_SETGET_STACK_FUNCS(super_root, struct btrfs_super_block, root, 64);+BTRFS_SETGET_STACK_FUNCS(super_sys_array_size,+			 struct btrfs_super_block, sys_chunk_array_size, 32);+BTRFS_SETGET_STACK_FUNCS(super_chunk_root_generation,+			 struct btrfs_super_block, chunk_root_generation, 64);+BTRFS_SETGET_STACK_FUNCS(super_root_level, struct btrfs_super_block,+			 root_level, 8);+BTRFS_SETGET_STACK_FUNCS(super_chunk_root, struct btrfs_super_block,+			 chunk_root, 64);+BTRFS_SETGET_STACK_FUNCS(super_chunk_root_level, struct btrfs_super_block,+			 chunk_root_level, 8);+BTRFS_SETGET_STACK_FUNCS(super_log_root, struct btrfs_super_block,+			 log_root, 64);+BTRFS_SETGET_STACK_FUNCS(super_log_root_transid, struct btrfs_super_block,+			 log_root_transid, 64);+BTRFS_SETGET_STACK_FUNCS(super_log_root_level, struct btrfs_super_block,+			 log_root_level, 8);+BTRFS_SETGET_STACK_FUNCS(super_total_bytes, struct btrfs_super_block,+			 total_bytes, 64);+BTRFS_SETGET_STACK_FUNCS(super_bytes_used, struct btrfs_super_block,+			 bytes_used, 64);+BTRFS_SETGET_STACK_FUNCS(super_sectorsize, struct btrfs_super_block,+			 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,+			 root_dir_objectid, 64);+BTRFS_SETGET_STACK_FUNCS(super_num_devices, struct btrfs_super_block,+			 num_devices, 64);+BTRFS_SETGET_STACK_FUNCS(super_compat_flags, struct btrfs_super_block,+			 compat_flags, 64);+BTRFS_SETGET_STACK_FUNCS(super_compat_ro_flags, struct btrfs_super_block,+			 compat_ro_flags, 64);+BTRFS_SETGET_STACK_FUNCS(super_incompat_flags, struct btrfs_super_block,+			 incompat_flags, 64);+BTRFS_SETGET_STACK_FUNCS(super_csum_type, struct btrfs_super_block,+			 csum_type, 16);+BTRFS_SETGET_STACK_FUNCS(super_cache_generation, struct btrfs_super_block,+			 cache_generation, 64);+BTRFS_SETGET_STACK_FUNCS(super_uuid_tree_generation, struct btrfs_super_block,+			 uuid_tree_generation, 64);+BTRFS_SETGET_STACK_FUNCS(super_magic, struct btrfs_super_block, magic, 64);++static inline int btrfs_super_csum_size(struct btrfs_super_block *s)+{+	int t = btrfs_super_csum_type(s);+	BUG_ON(t >= ARRAY_SIZE(btrfs_csum_sizes));+	return btrfs_csum_sizes[t];+}++static inline unsigned long btrfs_leaf_data(struct extent_buffer *l)+{+	return offsetof(struct btrfs_leaf, items);+}++/* struct btrfs_file_extent_item */+BTRFS_SETGET_FUNCS(file_extent_type, struct btrfs_file_extent_item, type, 8);+BTRFS_SETGET_STACK_FUNCS(stack_file_extent_type, struct btrfs_file_extent_item, type, 8);++static inline unsigned long btrfs_file_extent_inline_start(struct+						   btrfs_file_extent_item *e)+{+	unsigned long offset = (unsigned long)e;+	offset += offsetof(struct btrfs_file_extent_item, disk_bytenr);+	return offset;+}++static inline u32 btrfs_file_extent_calc_inline_size(u32 datasize)+{+	return offsetof(struct btrfs_file_extent_item, disk_bytenr) + datasize;+}++BTRFS_SETGET_FUNCS(file_extent_disk_bytenr, struct btrfs_file_extent_item,+		   disk_bytenr, 64);+BTRFS_SETGET_STACK_FUNCS(stack_file_extent_disk_bytenr, struct btrfs_file_extent_item,+		   disk_bytenr, 64);+BTRFS_SETGET_FUNCS(file_extent_generation, struct btrfs_file_extent_item,+		   generation, 64);+BTRFS_SETGET_STACK_FUNCS(stack_file_extent_generation, struct btrfs_file_extent_item,+		   generation, 64);+BTRFS_SETGET_FUNCS(file_extent_disk_num_bytes, struct btrfs_file_extent_item,+		   disk_num_bytes, 64);+BTRFS_SETGET_FUNCS(file_extent_offset, struct btrfs_file_extent_item,+		  offset, 64);+BTRFS_SETGET_STACK_FUNCS(stack_file_extent_offset, struct btrfs_file_extent_item,+		  offset, 64);+BTRFS_SETGET_FUNCS(file_extent_num_bytes, struct btrfs_file_extent_item,+		   num_bytes, 64);+BTRFS_SETGET_STACK_FUNCS(stack_file_extent_num_bytes, struct btrfs_file_extent_item,+		   num_bytes, 64);+BTRFS_SETGET_FUNCS(file_extent_ram_bytes, struct btrfs_file_extent_item,+		   ram_bytes, 64);+BTRFS_SETGET_STACK_FUNCS(stack_file_extent_ram_bytes, struct btrfs_file_extent_item,+		   ram_bytes, 64);+BTRFS_SETGET_FUNCS(file_extent_compression, struct btrfs_file_extent_item,+		   compression, 8);+BTRFS_SETGET_STACK_FUNCS(stack_file_extent_compression, struct btrfs_file_extent_item,+		   compression, 8);+BTRFS_SETGET_FUNCS(file_extent_encryption, struct btrfs_file_extent_item,+		   encryption, 8);+BTRFS_SETGET_FUNCS(file_extent_other_encoding, struct btrfs_file_extent_item,+		   other_encoding, 16);++/* btrfs_qgroup_status_item */+BTRFS_SETGET_FUNCS(qgroup_status_version, struct btrfs_qgroup_status_item,+		   version, 64);+BTRFS_SETGET_FUNCS(qgroup_status_generation, struct btrfs_qgroup_status_item,+		   generation, 64);+BTRFS_SETGET_FUNCS(qgroup_status_flags, struct btrfs_qgroup_status_item,+		   flags, 64);+BTRFS_SETGET_FUNCS(qgroup_status_scan, struct btrfs_qgroup_status_item,+		   scan, 64);++/* btrfs_qgroup_info_item */+BTRFS_SETGET_FUNCS(qgroup_info_generation, struct btrfs_qgroup_info_item,+		   generation, 64);+BTRFS_SETGET_FUNCS(qgroup_info_referenced, struct btrfs_qgroup_info_item,+		   referenced, 64);+BTRFS_SETGET_FUNCS(qgroup_info_referenced_compressed,+		   struct btrfs_qgroup_info_item, referenced_compressed, 64);+BTRFS_SETGET_FUNCS(qgroup_info_exclusive, struct btrfs_qgroup_info_item,+		   exclusive, 64);+BTRFS_SETGET_FUNCS(qgroup_info_exclusive_compressed,+		   struct btrfs_qgroup_info_item, exclusive_compressed, 64);++BTRFS_SETGET_STACK_FUNCS(stack_qgroup_info_generation,+			 struct btrfs_qgroup_info_item, generation, 64);+BTRFS_SETGET_STACK_FUNCS(stack_qgroup_info_referenced,+			 struct btrfs_qgroup_info_item, referenced, 64);+BTRFS_SETGET_STACK_FUNCS(stack_qgroup_info_referenced_compressed,+		   struct btrfs_qgroup_info_item, referenced_compressed, 64);+BTRFS_SETGET_STACK_FUNCS(stack_qgroup_info_exclusive,+			 struct btrfs_qgroup_info_item, exclusive, 64);+BTRFS_SETGET_STACK_FUNCS(stack_qgroup_info_exclusive_compressed,+		   struct btrfs_qgroup_info_item, exclusive_compressed, 64);++/* btrfs_qgroup_limit_item */+BTRFS_SETGET_FUNCS(qgroup_limit_flags, struct btrfs_qgroup_limit_item,+		   flags, 64);+BTRFS_SETGET_FUNCS(qgroup_limit_max_referenced, struct btrfs_qgroup_limit_item,+		   max_referenced, 64);+BTRFS_SETGET_FUNCS(qgroup_limit_max_exclusive, struct btrfs_qgroup_limit_item,+		   max_exclusive, 64);+BTRFS_SETGET_FUNCS(qgroup_limit_rsv_referenced, struct btrfs_qgroup_limit_item,+		   rsv_referenced, 64);+BTRFS_SETGET_FUNCS(qgroup_limit_rsv_exclusive, struct btrfs_qgroup_limit_item,+		   rsv_exclusive, 64);++BTRFS_SETGET_STACK_FUNCS(stack_qgroup_limit_flags,+			 struct btrfs_qgroup_limit_item, flags, 64);+BTRFS_SETGET_STACK_FUNCS(stack_qgroup_limit_max_referenced,+			 struct btrfs_qgroup_limit_item, max_referenced, 64);+BTRFS_SETGET_STACK_FUNCS(stack_qgroup_limit_max_exclusive,+			 struct btrfs_qgroup_limit_item, max_exclusive, 64);+BTRFS_SETGET_STACK_FUNCS(stack_qgroup_limit_rsv_referenced,+			 struct btrfs_qgroup_limit_item, rsv_referenced, 64);+BTRFS_SETGET_STACK_FUNCS(stack_qgroup_limit_rsv_exclusive,+			 struct btrfs_qgroup_limit_item, rsv_exclusive, 64);++/*+ * 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+ */+static inline u32 btrfs_file_extent_inline_item_len(struct extent_buffer *eb,+						    struct btrfs_item *e)+{+       unsigned long offset;+       offset = offsetof(struct btrfs_file_extent_item, disk_bytenr);+       return btrfs_item_size(eb, e) - offset;+}++/* 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);+}++static inline u32 btrfs_level_size(struct btrfs_root *root, int level) {+	if (level == 0)+		return root->leafsize;+	return root->nodesize;+}++static inline int 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);+}++/* helper function to cast into the data area of the leaf. */+#define btrfs_item_ptr(leaf, slot, type) \+	((type *)(btrfs_leaf_data(leaf) + \+	btrfs_item_offset_nr(leaf, slot)))++#define btrfs_item_ptr_offset(leaf, slot) \+	((unsigned long)(btrfs_leaf_data(leaf) + \+	btrfs_item_offset_nr(leaf, slot)))++/* extent-tree.c */+int btrfs_reserve_extent(struct btrfs_trans_handle *trans,+			 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);+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);+struct btrfs_block_group_cache *btrfs_lookup_block_group(struct+							 btrfs_fs_info *info,+							 u64 bytenr);+struct btrfs_block_group_cache *btrfs_lookup_first_block_group(struct+						       btrfs_fs_info *info,+						       u64 bytenr);+struct extent_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,+					struct btrfs_root *root,+					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,+			     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_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_extent(struct btrfs_trans_handle *trans,+		      struct btrfs_root *root,+		      u64 bytenr, u64 num_bytes, u64 parent,+		      u64 root_objectid, u64 owner, u64 offset);+int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans,+			       struct btrfs_root *root,+			       struct extent_io_tree *unpin);+int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,+				struct btrfs_root *root,+				u64 bytenr, u64 num_bytes, u64 parent,+				u64 root_objectid, u64 ref_generation,+				u64 owner_objectid);+int btrfs_update_extent_ref(struct btrfs_trans_handle *trans,+			    struct btrfs_root *root, u64 bytenr,+			    u64 orig_parent, u64 parent,+			    u64 root_objectid, u64 ref_generation,+			    u64 owner_objectid);+int btrfs_write_dirty_block_groups(struct btrfs_trans_handle *trans,+				    struct btrfs_root *root);+int btrfs_free_block_groups(struct btrfs_fs_info *info);+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);+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);+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,+			     int alloc, int mark_free);+int btrfs_record_file_extent(struct btrfs_trans_handle *trans,+			      struct btrfs_root *root, u64 objectid,+			      struct btrfs_inode_item *inode,+			      u64 file_pos, u64 disk_bytenr,+			      u64 num_bytes);+/* 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);+enum btrfs_tree_block_status+btrfs_check_node(struct btrfs_root *root, struct btrfs_disk_key *parent_key,+		 struct extent_buffer *buf);+enum btrfs_tree_block_status+btrfs_check_leaf(struct btrfs_root *root, struct btrfs_disk_key *parent_key,+		 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 *parent, int slot);+int btrfs_previous_item(struct btrfs_root *root,+			struct btrfs_path *path, u64 min_objectid,+			int type);+int btrfs_cow_block(struct btrfs_trans_handle *trans,+		    struct btrfs_root *root, struct extent_buffer *buf,+		    struct extent_buffer *parent, int parent_slot,+		    struct extent_buffer **cow_ret);+int __btrfs_cow_block(struct btrfs_trans_handle *trans,+			     struct btrfs_root *root,+			     struct extent_buffer *buf,+			     struct extent_buffer *parent, int parent_slot,+			     struct extent_buffer **cow_ret,+			     u64 search_start, u64 empty_size);+int btrfs_copy_root(struct btrfs_trans_handle *trans,+		      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,+			u32 new_size, int from_end);+int btrfs_split_item(struct btrfs_trans_handle *trans,+		     struct btrfs_root *root,+		     struct btrfs_path *path,+		     struct btrfs_key *new_key,+		     unsigned long split_offset);+int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root+		      *root, struct btrfs_key *key, struct btrfs_path *p, int+		      ins_len, int cow);+void btrfs_release_path(struct btrfs_path *p);+void add_root_to_dirty_list(struct btrfs_root *root);+struct btrfs_path *btrfs_alloc_path(void);+void btrfs_free_path(struct btrfs_path *p);+void btrfs_init_path(struct btrfs_path *p);+int btrfs_del_items(struct btrfs_trans_handle *trans, struct btrfs_root *root,+		   struct btrfs_path *path, int slot, int nr);++static inline int btrfs_del_item(struct btrfs_trans_handle *trans,+				 struct btrfs_root *root,+				 struct btrfs_path *path)+{+	return btrfs_del_items(trans, root, path, path->slots[0], 1);+}++int btrfs_insert_item(struct btrfs_trans_handle *trans, struct btrfs_root+		      *root, struct btrfs_key *key, void *data, u32 data_size);+int btrfs_insert_empty_items(struct btrfs_trans_handle *trans,+			     struct btrfs_root *root,+			     struct btrfs_path *path,+			     struct btrfs_key *cpu_key, u32 *data_size, int nr);++static inline int btrfs_insert_empty_item(struct btrfs_trans_handle *trans,+					  struct btrfs_root *root,+					  struct btrfs_path *path,+					  struct btrfs_key *key,+					  u32 data_size)+{+	return btrfs_insert_empty_items(trans, root, path, key, &data_size, 1);+}++int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path);+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);+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,+			    struct btrfs_key *new_key);+void btrfs_set_item_key_unsafe(struct btrfs_root *root,+			       struct btrfs_path *path,+			       struct btrfs_key *new_key);++/* root-item.c */+int btrfs_add_root_ref(struct btrfs_trans_handle *trans,+		       struct btrfs_root *tree_root,+		       u64 root_id, u8 type, u64 ref_id,+		       u64 dirid, u64 sequence,+		       const char *name, int name_len);+int btrfs_insert_root(struct btrfs_trans_handle *trans, struct btrfs_root+		      *root, struct btrfs_key *key, struct btrfs_root_item+		      *item);+int btrfs_update_root(struct btrfs_trans_handle *trans, struct btrfs_root+		      *root, struct btrfs_key *key, struct btrfs_root_item+		      *item);+int btrfs_find_last_root(struct btrfs_root *root, u64 objectid, struct+			 btrfs_root_item *item, struct btrfs_key *key);+/* dir-item.c */+int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root+			  *root, const char *name, int name_len, u64 dir,+			  struct btrfs_key *location, u8 type, u64 index);+struct btrfs_dir_item *btrfs_lookup_dir_item(struct btrfs_trans_handle *trans,+					     struct btrfs_root *root,+					     struct btrfs_path *path, u64 dir,+					     const char *name, int name_len,+					     int mod);+int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans,+			    struct btrfs_root *root, const char *name,+			    u16 name_len, const void *data, u16 data_len,+			    u64 dir);+/* inode-map.c */+int btrfs_find_free_objectid(struct btrfs_trans_handle *trans,+			     struct btrfs_root *fs_root,+			     u64 dirid, u64 *objectid);++/* inode-item.c */+int btrfs_insert_inode_ref(struct btrfs_trans_handle *trans,+			   struct btrfs_root *root,+			   const char *name, int name_len,+			   u64 inode_objectid, u64 ref_objectid, u64 index);+int btrfs_insert_inode(struct btrfs_trans_handle *trans, struct btrfs_root+		       *root, u64 objectid, struct btrfs_inode_item+		       *inode_item);+int btrfs_lookup_inode(struct btrfs_trans_handle *trans, struct btrfs_root+		       *root, struct btrfs_path *path,+		       struct btrfs_key *location, int mod);++/* file-item.c */+int btrfs_del_csums(struct btrfs_trans_handle *trans,+		    struct btrfs_root *root, u64 bytenr, u64 len);+int btrfs_insert_file_extent(struct btrfs_trans_handle *trans,+			     struct btrfs_root *root,+			     u64 objectid, u64 pos, u64 offset,+			     u64 disk_num_bytes,+			     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);+int btrfs_csum_file_block(struct btrfs_trans_handle *trans,+			  struct btrfs_root *root, u64 alloc_end,+			  u64 bytenr, char *data, size_t len);+int btrfs_csum_truncate(struct btrfs_trans_handle *trans,+			struct btrfs_root *root, struct btrfs_path *path,+			u64 isize);++/* uuid-tree.c */+int btrfs_lookup_uuid_subvol_item(int fd, const u8 *uuid, u64 *subvol_id);+int btrfs_lookup_uuid_received_subvol_item(int fd, const u8 *uuid,+					   u64 *subvol_id);+#endif
+ include/btrfs/extent-cache.h view
@@ -0,0 +1,81 @@+/*+ * Copyright (C) 2007 Oracle.  All rights reserved.+ *+ * This program is free software; you can redistribute it and/or+ * modify it under the terms of the GNU General Public+ * License v2 as published by the Free Software Foundation.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU+ * General Public License for more details.+ *+ * You should have received a copy of the GNU General Public+ * License along with this program; if not, write to the+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,+ * Boston, MA 021110-1307, USA.+ */++#ifndef __EXTENT_CACHE_H__+#define __EXTENT_CACHE_H__++#if BTRFS_FLAT_INCLUDES+#include "kerncompat.h"+#include "rbtree.h"+#else+#include <btrfs/kerncompat.h>+#include <btrfs/rbtree.h>+#endif /* BTRFS_FLAT_INCLUDES */++struct cache_tree {+	struct rb_root root;+};++struct cache_extent {+	struct rb_node rb_node;+	u64 objectid;+	u64 start;+	u64 size;+};++void cache_tree_init(struct cache_tree *tree);++struct cache_extent *first_cache_extent(struct cache_tree *tree);+struct cache_extent *prev_cache_extent(struct cache_extent *pe);+struct cache_extent *next_cache_extent(struct cache_extent *pe);++struct cache_extent *search_cache_extent(struct cache_tree *tree, u64 start);+struct cache_extent *lookup_cache_extent(struct cache_tree *tree,+					 u64 start, u64 size);++int add_cache_extent(struct cache_tree *tree, u64 start, u64 size);+int insert_cache_extent(struct cache_tree *tree, struct cache_extent *pe);+void remove_cache_extent(struct cache_tree *tree, struct cache_extent *pe);++static inline int cache_tree_empty(struct cache_tree *tree)+{+	return RB_EMPTY_ROOT(&tree->root);+}++typedef void (*free_cache_extent)(struct cache_extent *pe);++void cache_tree_free_extents(struct cache_tree *tree,+			     free_cache_extent free_func);++#define FREE_EXTENT_CACHE_BASED_TREE(name, free_func)		\+static void free_##name##_tree(struct cache_tree *tree)		\+{								\+	cache_tree_free_extents(tree, free_func);		\+}++void free_extent_cache_tree(struct cache_tree *tree);++struct cache_extent *search_cache_extent2(struct cache_tree *tree,+					  u64 objectid, u64 start);+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);++#endif
+ include/btrfs/extent_io.h view
@@ -0,0 +1,137 @@+/*+ * Copyright (C) 2007 Oracle.  All rights reserved.+ *+ * This program is free software; you can redistribute it and/or+ * modify it under the terms of the GNU General Public+ * License v2 as published by the Free Software Foundation.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU+ * General Public License for more details.+ *+ * You should have received a copy of the GNU General Public+ * License along with this program; if not, write to the+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,+ * Boston, MA 021110-1307, USA.+ */++#ifndef __EXTENTMAP__+#define __EXTENTMAP__++#if BTRFS_FLAT_INCLUDES+#include "kerncompat.h"+#include "extent-cache.h"+#include "list.h"+#else+#include <btrfs/kerncompat.h>+#include <btrfs/extent-cache.h>+#include <btrfs/list.h>+#endif /* BTRFS_FLAT_INCLUDES */++#define EXTENT_DIRTY 1+#define EXTENT_WRITEBACK (1 << 1)+#define EXTENT_UPTODATE (1 << 2)+#define EXTENT_LOCKED (1 << 3)+#define EXTENT_NEW (1 << 4)+#define EXTENT_DELALLOC (1 << 5)+#define EXTENT_DEFRAG (1 << 6)+#define EXTENT_DEFRAG_DONE (1 << 7)+#define EXTENT_BUFFER_FILLED (1 << 8)+#define EXTENT_CSUM (1 << 9)+#define EXTENT_BAD_TRANSID (1 << 10)+#define EXTENT_IOBITS (EXTENT_LOCKED | EXTENT_WRITEBACK)++#define BLOCK_GROUP_DATA     EXTENT_WRITEBACK+#define BLOCK_GROUP_METADATA EXTENT_UPTODATE+#define BLOCK_GROUP_SYSTEM   EXTENT_NEW++#define BLOCK_GROUP_DIRTY EXTENT_DIRTY++struct btrfs_fs_info;++struct extent_io_tree {+	struct cache_tree state;+	struct cache_tree cache;+	struct list_head lru;+	u64 cache_size;+};++struct extent_state {+	struct cache_extent cache_node;+	u64 start;+	u64 end;+	int refs;+	unsigned long state;+	u64 xprivate;+};++struct extent_buffer {+	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;+	int refs;+	int flags;+	int fd;+	char data[];+};++static inline void extent_buffer_get(struct extent_buffer *eb)+{+	eb->refs++;+}++void extent_io_tree_init(struct extent_io_tree *tree);+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 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 extent_buffer_uptodate(struct extent_buffer *eb);+int set_extent_buffer_uptodate(struct extent_buffer *eb);+int clear_extent_buffer_uptodate(struct extent_io_tree *tree,+				struct extent_buffer *eb);+int set_state_private(struct extent_io_tree *tree, u64 start, u64 xprivate);+int get_state_private(struct extent_io_tree *tree, u64 start, u64 *xprivate);+struct extent_buffer *find_extent_buffer(struct extent_io_tree *tree,+					 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,+					  u64 bytenr, u32 blocksize);+void free_extent_buffer(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);+int memcmp_extent_buffer(struct extent_buffer *eb, const void *ptrv,+			 unsigned long start, unsigned long len);+void read_extent_buffer(struct extent_buffer *eb, void *dst,+			unsigned long start, unsigned long len);+void write_extent_buffer(struct extent_buffer *eb, const void *src,+			 unsigned long start, unsigned long len);+void copy_extent_buffer(struct extent_buffer *dst, struct extent_buffer *src,+			unsigned long dst_offset, unsigned long src_offset,+			unsigned long len);+void memmove_extent_buffer(struct extent_buffer *dst, unsigned long dst_offset,+			   unsigned long src_offset, unsigned long len);+void memset_extent_buffer(struct extent_buffer *eb, char c,+			  unsigned long start, unsigned long len);+int set_extent_buffer_dirty(struct extent_buffer *eb);+int clear_extent_buffer_dirty(struct extent_buffer *eb);+int read_data_from_disk(struct btrfs_fs_info *info, void *buf, u64 offset,+			u64 bytes, int mirror);+int write_data_to_disk(struct btrfs_fs_info *info, void *buf, u64 offset,+		       u64 bytes, int mirror);+#endif
+ include/btrfs/ioctl.h view
@@ -0,0 +1,609 @@+/*+ * Copyright (C) 2007 Oracle.  All rights reserved.+ *+ * This program is free software; you can redistribute it and/or+ * modify it under the terms of the GNU General Public+ * License v2 as published by the Free Software Foundation.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU+ * General Public License for more details.+ *+ * You should have received a copy of the GNU General Public+ * License along with this program; if not, write to the+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,+ * Boston, MA 021110-1307, USA.+ */++#ifndef __IOCTL_+#define __IOCTL_+#include <asm/types.h>+#include <linux/ioctl.h>+#include <time.h>++#ifdef __cplusplus+extern "C" {+#endif++#define BTRFS_IOCTL_MAGIC 0x94+#define BTRFS_VOL_NAME_MAX 255++/* this should be 4k */+#define BTRFS_PATH_NAME_MAX 4087+struct btrfs_ioctl_vol_args {+	__s64 fd;+	char name[BTRFS_PATH_NAME_MAX + 1];+};++#define BTRFS_DEVICE_PATH_NAME_MAX 1024++#define BTRFS_SUBVOL_CREATE_ASYNC	(1ULL << 0)+#define BTRFS_SUBVOL_RDONLY		(1ULL << 1)+#define BTRFS_SUBVOL_QGROUP_INHERIT	(1ULL << 2)++#define BTRFS_QGROUP_INHERIT_SET_LIMITS	(1ULL << 0)++struct btrfs_qgroup_limit {+	__u64	flags;+	__u64	max_referenced;+	__u64	max_exclusive;+	__u64	rsv_referenced;+	__u64	rsv_exclusive;+};++struct btrfs_qgroup_inherit {+	__u64	flags;+	__u64	num_qgroups;+	__u64	num_ref_copies;+	__u64	num_excl_copies;+	struct btrfs_qgroup_limit lim;+	__u64	qgroups[0];+};++struct btrfs_ioctl_qgroup_limit_args {+	__u64	qgroupid;+	struct btrfs_qgroup_limit lim;+};++#define BTRFS_SUBVOL_NAME_MAX 4039++struct btrfs_ioctl_vol_args_v2 {+	__s64 fd;+	__u64 transid;+	__u64 flags;+	union {+		struct {+			__u64 size;+			struct btrfs_qgroup_inherit *qgroup_inherit;+		};+		__u64 unused[4];+	};+	char name[BTRFS_SUBVOL_NAME_MAX + 1];+};++#define BTRFS_FSID_SIZE 16+#define BTRFS_UUID_SIZE 16++struct btrfs_scrub_progress {+	__u64 data_extents_scrubbed;+	__u64 tree_extents_scrubbed;+	__u64 data_bytes_scrubbed;+	__u64 tree_bytes_scrubbed;+	__u64 read_errors;+	__u64 csum_errors;+	__u64 verify_errors;+	__u64 no_csum;+	__u64 csum_discards;+	__u64 super_errors;+	__u64 malloc_errors;+	__u64 uncorrectable_errors;+	__u64 corrected_errors;+	__u64 last_physical;+	__u64 unverified_errors;+};++#define BTRFS_SCRUB_READONLY	1+struct btrfs_ioctl_scrub_args {+	__u64 devid;				/* in */+	__u64 start;				/* in */+	__u64 end;				/* in */+	__u64 flags;				/* in */+	struct btrfs_scrub_progress progress;	/* out */+	/* pad to 1k */+	__u64 unused[(1024-32-sizeof(struct btrfs_scrub_progress))/8];+};++#define BTRFS_IOCTL_DEV_REPLACE_CONT_READING_FROM_SRCDEV_MODE_ALWAYS	0+#define BTRFS_IOCTL_DEV_REPLACE_CONT_READING_FROM_SRCDEV_MODE_AVOID	1+struct btrfs_ioctl_dev_replace_start_params {+	__u64 srcdevid;	/* in, if 0, use srcdev_name instead */+	__u64 cont_reading_from_srcdev_mode;	/* in, see #define+						 * above */+	__u8 srcdev_name[BTRFS_DEVICE_PATH_NAME_MAX + 1];	/* in */+	__u8 tgtdev_name[BTRFS_DEVICE_PATH_NAME_MAX + 1];	/* in */+};++#define BTRFS_IOCTL_DEV_REPLACE_STATE_NEVER_STARTED	0+#define BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED		1+#define BTRFS_IOCTL_DEV_REPLACE_STATE_FINISHED		2+#define BTRFS_IOCTL_DEV_REPLACE_STATE_CANCELED		3+#define BTRFS_IOCTL_DEV_REPLACE_STATE_SUSPENDED		4+struct btrfs_ioctl_dev_replace_status_params {+	__u64 replace_state;	/* out, see #define above */+	__u64 progress_1000;	/* out, 0 <= x <= 1000 */+	__u64 time_started;	/* out, seconds since 1-Jan-1970 */+	__u64 time_stopped;	/* out, seconds since 1-Jan-1970 */+	__u64 num_write_errors;	/* out */+	__u64 num_uncorrectable_read_errors;	/* out */+};++#define BTRFS_IOCTL_DEV_REPLACE_CMD_START			0+#define BTRFS_IOCTL_DEV_REPLACE_CMD_STATUS			1+#define BTRFS_IOCTL_DEV_REPLACE_CMD_CANCEL			2+#define BTRFS_IOCTL_DEV_REPLACE_RESULT_NO_ERROR			0+#define BTRFS_IOCTL_DEV_REPLACE_RESULT_NOT_STARTED		1+#define BTRFS_IOCTL_DEV_REPLACE_RESULT_ALREADY_STARTED		2+struct btrfs_ioctl_dev_replace_args {+	__u64 cmd;	/* in */+	__u64 result;	/* out */++	union {+		struct btrfs_ioctl_dev_replace_start_params start;+		struct btrfs_ioctl_dev_replace_status_params status;+	};	/* in/out */++	__u64 spare[64];+};++struct btrfs_ioctl_dev_info_args {+	__u64 devid;				/* in/out */+	__u8 uuid[BTRFS_UUID_SIZE];		/* in/out */+	__u64 bytes_used;			/* out */+	__u64 total_bytes;			/* out */+	__u64 unused[379];			/* pad to 4k */+	__u8 path[BTRFS_DEVICE_PATH_NAME_MAX];	/* out */+};++struct btrfs_ioctl_fs_info_args {+	__u64 max_id;				/* out */+	__u64 num_devices;			/* out */+	__u8 fsid[BTRFS_FSID_SIZE];		/* out */+	__u64 reserved[124];			/* pad to 1k */+};++/* balance control ioctl modes */+#define BTRFS_BALANCE_CTL_PAUSE		1+#define BTRFS_BALANCE_CTL_CANCEL	2+#define BTRFS_BALANCE_CTL_RESUME	3++/*+ * this is packed, because it should be exactly the same as its disk+ * byte order counterpart (struct btrfs_disk_balance_args)+ */+struct btrfs_balance_args {+	__u64 profiles;+	__u64 usage;+	__u64 devid;+	__u64 pstart;+	__u64 pend;+	__u64 vstart;+	__u64 vend;++	__u64 target;++	__u64 flags;++	__u64 unused[8];+} __attribute__ ((__packed__));++struct btrfs_balance_progress {+	__u64 expected;+	__u64 considered;+	__u64 completed;+};++#define BTRFS_BALANCE_STATE_RUNNING	(1ULL << 0)+#define BTRFS_BALANCE_STATE_PAUSE_REQ	(1ULL << 1)+#define BTRFS_BALANCE_STATE_CANCEL_REQ	(1ULL << 2)++struct btrfs_ioctl_balance_args {+	__u64 flags;				/* in/out */+	__u64 state;				/* out */++	struct btrfs_balance_args data;		/* in/out */+	struct btrfs_balance_args meta;		/* in/out */+	struct btrfs_balance_args sys;		/* in/out */++	struct btrfs_balance_progress stat;	/* out */++	__u64 unused[72];			/* pad to 1k */+};++struct btrfs_ioctl_search_key {+	/* which root are we searching.  0 is the tree of tree roots */+	__u64 tree_id;++	/* keys returned will be >= min and <= max */+	__u64 min_objectid;+	__u64 max_objectid;++	/* keys returned will be >= min and <= max */+	__u64 min_offset;+	__u64 max_offset;++	/* max and min transids to search for */+	__u64 min_transid;+	__u64 max_transid;++	/* keys returned will be >= min and <= max */+	__u32 min_type;+	__u32 max_type;++	/*+	 * how many items did userland ask for, and how many are we+	 * returning+	 */+	__u32 nr_items;++	/* align to 64 bits */+	__u32 unused;++	/* some extra for later */+	__u64 unused1;+	__u64 unused2;+	__u64 unused3;+	__u64 unused4;+};++struct btrfs_ioctl_search_header {+	__u64 transid;+	__u64 objectid;+	__u64 offset;+	__u32 type;+	__u32 len;+} __attribute__((may_alias));++#define BTRFS_SEARCH_ARGS_BUFSIZE (4096 - sizeof(struct btrfs_ioctl_search_key))+/*+ * the buf is an array of search headers where+ * each header is followed by the actual item+ * the type field is expanded to 32 bits for alignment+ */+struct btrfs_ioctl_search_args {+	struct btrfs_ioctl_search_key key;+	char buf[BTRFS_SEARCH_ARGS_BUFSIZE];+};++#define BTRFS_INO_LOOKUP_PATH_MAX 4080+struct btrfs_ioctl_ino_lookup_args {+	__u64 treeid;+	__u64 objectid;+	char name[BTRFS_INO_LOOKUP_PATH_MAX];+};++/* flags for the defrag range ioctl */+#define BTRFS_DEFRAG_RANGE_COMPRESS 1+#define BTRFS_DEFRAG_RANGE_START_IO 2++struct btrfs_ioctl_defrag_range_args {+	/* start of the defrag operation */+	__u64 start;++	/* number of bytes to defrag, use (u64)-1 to say all */+	__u64 len;++	/*+	 * flags for the operation, which can include turning+	 * on compression for this one defrag+	 */+	__u64 flags;++	/*+	 * any extent bigger than this will be considered+	 * already defragged.  Use 0 to take the kernel default+	 * Use 1 to say every single extent must be rewritten+	 */+	__u32 extent_thresh;++	/*+	 * which compression method to use if turning on compression+	 * for this defrag operation.  If unspecified, zlib will+	 * be used+	 */+	__u32 compress_type;++	/* spare for later */+	__u32 unused[4];+};++struct btrfs_ioctl_space_info {+	__u64 flags;+	__u64 total_bytes;+	__u64 used_bytes;+};++struct btrfs_ioctl_space_args {+	__u64 space_slots;+	__u64 total_spaces;+	struct btrfs_ioctl_space_info spaces[0];+};++struct btrfs_data_container {+	__u32	bytes_left;	/* out -- bytes not needed to deliver output */+	__u32	bytes_missing;	/* out -- additional bytes needed for result */+	__u32	elem_cnt;	/* out */+	__u32	elem_missed;	/* out */+	__u64	val[0];		/* out */+};++struct btrfs_ioctl_ino_path_args {+	__u64				inum;		/* in */+	__u64				size;		/* in */+	__u64				reserved[4];+	/* struct btrfs_data_container	*fspath;	   out */+	__u64				fspath;		/* out */+};++struct btrfs_ioctl_logical_ino_args {+	__u64				logical;	/* in */+	__u64				size;		/* in */+	__u64				reserved[4];+	/* struct btrfs_data_container	*inodes;	out   */+	__u64				inodes;+};++struct btrfs_ioctl_timespec {+	__u64 sec;+	__u32 nsec;+};++struct btrfs_ioctl_received_subvol_args {+	char	uuid[BTRFS_UUID_SIZE];	/* in */+	__u64	stransid;		/* in */+	__u64	rtransid;		/* out */+	struct btrfs_ioctl_timespec stime; /* in */+	struct btrfs_ioctl_timespec rtime; /* out */+	__u64	flags;			/* in */+	__u64	reserved[16];		/* in */+};++/*+ * 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.+ */+#define BTRFS_SEND_FLAG_NO_FILE_DATA		0x1++/*+ * Do not add the leading stream header. Used when multiple snapshots+ * are sent back to back.+ */+#define BTRFS_SEND_FLAG_OMIT_STREAM_HEADER	0x2++/*+ * Omit the command at the end of the stream that indicated the end+ * of the stream. This option is used when multiple snapshots are+ * sent back to back.+ */+#define BTRFS_SEND_FLAG_OMIT_END_CMD		0x4++struct btrfs_ioctl_send_args {+	__s64 send_fd;			/* in */+	__u64 clone_sources_count;	/* in */+	__u64 *clone_sources;		/* in */+	__u64 parent_root;		/* in */+	__u64 flags;			/* in */+	__u64 reserved[4];		/* in */+};++enum btrfs_dev_stat_values {+	/* disk I/O failure stats */+	BTRFS_DEV_STAT_WRITE_ERRS, /* EIO or EREMOTEIO from lower layers */+	BTRFS_DEV_STAT_READ_ERRS, /* EIO or EREMOTEIO from lower layers */+	BTRFS_DEV_STAT_FLUSH_ERRS, /* EIO or EREMOTEIO from lower layers */++	/* stats for indirect indications for I/O failures */+	BTRFS_DEV_STAT_CORRUPTION_ERRS, /* checksum error, bytenr error or+					 * contents is illegal: this is an+					 * indication that the block was damaged+					 * during read or write, or written to+					 * wrong location or read from wrong+					 * location */+	BTRFS_DEV_STAT_GENERATION_ERRS, /* an indication that blocks have not+					 * been written */++	BTRFS_DEV_STAT_VALUES_MAX+};++/* Reset statistics after reading; needs SYS_ADMIN capability */+#define	BTRFS_DEV_STATS_RESET		(1ULL << 0)++struct btrfs_ioctl_get_dev_stats {+	__u64 devid;				/* in */+	__u64 nr_items;				/* in/out */+	__u64 flags;				/* in/out */++	/* out values: */+	__u64 values[BTRFS_DEV_STAT_VALUES_MAX];++	__u64 unused[128 - 2 - BTRFS_DEV_STAT_VALUES_MAX]; /* pad to 1k */+};++/* BTRFS_IOC_SNAP_CREATE is no longer used by the btrfs command */+#define BTRFS_QUOTA_CTL_ENABLE	1+#define BTRFS_QUOTA_CTL_DISABLE	2+/* 3 has formerly been reserved for BTRFS_QUOTA_CTL_RESCAN */+struct btrfs_ioctl_quota_ctl_args {+	__u64 cmd;+	__u64 status;+};++struct btrfs_ioctl_quota_rescan_args {+	__u64	flags;+	__u64   progress;+	__u64   reserved[6];+};++struct btrfs_ioctl_qgroup_assign_args {+	__u64 assign;+	__u64 src;+	__u64 dst;+};++struct btrfs_ioctl_qgroup_create_args {+	__u64 create;+	__u64 qgroupid;+};++/* Error codes as returned by the kernel */+enum btrfs_err_code {+	notused,+	BTRFS_ERROR_DEV_RAID1_MIN_NOT_MET,+	BTRFS_ERROR_DEV_RAID10_MIN_NOT_MET,+	BTRFS_ERROR_DEV_RAID5_MIN_NOT_MET,+	BTRFS_ERROR_DEV_RAID6_MIN_NOT_MET,+	BTRFS_ERROR_DEV_TGT_REPLACE,+	BTRFS_ERROR_DEV_MISSING_NOT_FOUND,+	BTRFS_ERROR_DEV_ONLY_WRITABLE,+	BTRFS_ERROR_DEV_EXCL_RUN_IN_PROGRESS+};++/* An error code to error string mapping for the kernel+*  error codes+*/+static inline char *btrfs_err_str(enum btrfs_err_code err_code)+{+	switch (err_code) {+		case BTRFS_ERROR_DEV_RAID1_MIN_NOT_MET:+			return "unable to go below two devices on raid1";+		case BTRFS_ERROR_DEV_RAID10_MIN_NOT_MET:+			return "unable to go below four devices on raid10";+		case BTRFS_ERROR_DEV_RAID5_MIN_NOT_MET:+			return "unable to go below two devices on raid5";+		case BTRFS_ERROR_DEV_RAID6_MIN_NOT_MET:+			return "unable to go below three devices on raid6";+		case BTRFS_ERROR_DEV_TGT_REPLACE:+			return "unable to remove the dev_replace target dev";+		case BTRFS_ERROR_DEV_MISSING_NOT_FOUND:+			return "no missing devices found to remove";+		case BTRFS_ERROR_DEV_ONLY_WRITABLE:+			return "unable to remove the only writeable device";+		case BTRFS_ERROR_DEV_EXCL_RUN_IN_PROGRESS:+			return "add/delete/balance/replace/resize operation "+				"in progress";+		default:+			return NULL;+	}+}++#define BTRFS_IOC_SNAP_CREATE _IOW(BTRFS_IOCTL_MAGIC, 1, \+				   struct btrfs_ioctl_vol_args)+#define BTRFS_IOC_DEFRAG _IOW(BTRFS_IOCTL_MAGIC, 2, \+				   struct btrfs_ioctl_vol_args)+#define BTRFS_IOC_RESIZE _IOW(BTRFS_IOCTL_MAGIC, 3, \+				   struct btrfs_ioctl_vol_args)+#define BTRFS_IOC_SCAN_DEV _IOW(BTRFS_IOCTL_MAGIC, 4, \+				   struct btrfs_ioctl_vol_args)++/* With a @src_length of zero, the range from @src_offset->EOF is cloned! */+struct btrfs_ioctl_clone_range_args {+	__s64 src_fd;+	__u64 src_offset, src_length;+	__u64 dest_offset;+};++/* trans start and trans end are dangerous, and only for+ * use by applications that know how to avoid the+ * resulting deadlocks+ */+#define BTRFS_IOC_TRANS_START  _IO(BTRFS_IOCTL_MAGIC, 6)+#define BTRFS_IOC_TRANS_END    _IO(BTRFS_IOCTL_MAGIC, 7)+#define BTRFS_IOC_SYNC         _IO(BTRFS_IOCTL_MAGIC, 8)++#define BTRFS_IOC_CLONE        _IOW(BTRFS_IOCTL_MAGIC, 9, int)+#define BTRFS_IOC_ADD_DEV _IOW(BTRFS_IOCTL_MAGIC, 10, \+				   struct btrfs_ioctl_vol_args)+#define BTRFS_IOC_RM_DEV _IOW(BTRFS_IOCTL_MAGIC, 11, \+				   struct btrfs_ioctl_vol_args)+#define BTRFS_IOC_BALANCE _IOW(BTRFS_IOCTL_MAGIC, 12, \+				   struct btrfs_ioctl_vol_args)+#define BTRFS_IOC_CLONE_RANGE _IOW(BTRFS_IOCTL_MAGIC, 13, \+				   struct btrfs_ioctl_clone_range_args)+#define BTRFS_IOC_SUBVOL_CREATE _IOW(BTRFS_IOCTL_MAGIC, 14, \+				   struct btrfs_ioctl_vol_args)+#define BTRFS_IOC_SNAP_DESTROY _IOW(BTRFS_IOCTL_MAGIC, 15, \+				   struct btrfs_ioctl_vol_args)+#define BTRFS_IOC_DEFRAG_RANGE _IOW(BTRFS_IOCTL_MAGIC, 16, \+				struct btrfs_ioctl_defrag_range_args)+#define BTRFS_IOC_TREE_SEARCH _IOWR(BTRFS_IOCTL_MAGIC, 17, \+				   struct btrfs_ioctl_search_args)+#define BTRFS_IOC_INO_LOOKUP _IOWR(BTRFS_IOCTL_MAGIC, 18, \+				   struct btrfs_ioctl_ino_lookup_args)+#define BTRFS_IOC_DEFAULT_SUBVOL _IOW(BTRFS_IOCTL_MAGIC, 19, __u64)+#define BTRFS_IOC_SPACE_INFO _IOWR(BTRFS_IOCTL_MAGIC, 20, \+				    struct btrfs_ioctl_space_args)+#define BTRFS_IOC_START_SYNC _IOR(BTRFS_IOCTL_MAGIC, 24, __u64)+#define BTRFS_IOC_WAIT_SYNC  _IOW(BTRFS_IOCTL_MAGIC, 22, __u64)+#define BTRFS_IOC_SNAP_CREATE_V2 _IOW(BTRFS_IOCTL_MAGIC, 23, \+				   struct btrfs_ioctl_vol_args_v2)+#define BTRFS_IOC_SUBVOL_CREATE_V2 _IOW(BTRFS_IOCTL_MAGIC, 24, \+				   struct btrfs_ioctl_vol_args_v2)+#define BTRFS_IOC_SUBVOL_GETFLAGS _IOR(BTRFS_IOCTL_MAGIC, 25, __u64)+#define BTRFS_IOC_SUBVOL_SETFLAGS _IOW(BTRFS_IOCTL_MAGIC, 26, __u64)+#define BTRFS_IOC_SCRUB _IOWR(BTRFS_IOCTL_MAGIC, 27, \+				struct btrfs_ioctl_scrub_args)+#define BTRFS_IOC_SCRUB_CANCEL _IO(BTRFS_IOCTL_MAGIC, 28)+#define BTRFS_IOC_SCRUB_PROGRESS _IOWR(BTRFS_IOCTL_MAGIC, 29, \+					struct btrfs_ioctl_scrub_args)+#define BTRFS_IOC_DEV_INFO _IOWR(BTRFS_IOCTL_MAGIC, 30, \+					struct btrfs_ioctl_dev_info_args)+#define BTRFS_IOC_FS_INFO _IOR(BTRFS_IOCTL_MAGIC, 31, \+                                 struct btrfs_ioctl_fs_info_args)+#define BTRFS_IOC_BALANCE_V2 _IOWR(BTRFS_IOCTL_MAGIC, 32, \+				   struct btrfs_ioctl_balance_args)+#define BTRFS_IOC_BALANCE_CTL _IOW(BTRFS_IOCTL_MAGIC, 33, int)+#define BTRFS_IOC_BALANCE_PROGRESS _IOR(BTRFS_IOCTL_MAGIC, 34, \+					struct btrfs_ioctl_balance_args)+#define BTRFS_IOC_INO_PATHS _IOWR(BTRFS_IOCTL_MAGIC, 35, \+					struct btrfs_ioctl_ino_path_args)+#define BTRFS_IOC_LOGICAL_INO _IOWR(BTRFS_IOCTL_MAGIC, 36, \+					struct btrfs_ioctl_ino_path_args)+#define BTRFS_IOC_DEVICES_READY _IOR(BTRFS_IOCTL_MAGIC, 39, \+				     struct btrfs_ioctl_vol_args)+#define BTRFS_IOC_SET_RECEIVED_SUBVOL _IOWR(BTRFS_IOCTL_MAGIC, 37, \+				struct btrfs_ioctl_received_subvol_args)+#define BTRFS_IOC_SEND _IOW(BTRFS_IOCTL_MAGIC, 38, struct btrfs_ioctl_send_args)++#define BTRFS_IOC_QUOTA_CTL _IOWR(BTRFS_IOCTL_MAGIC, 40, \+					struct btrfs_ioctl_quota_ctl_args)+#define BTRFS_IOC_QGROUP_ASSIGN _IOW(BTRFS_IOCTL_MAGIC, 41, \+					struct btrfs_ioctl_qgroup_assign_args)+#define BTRFS_IOC_QGROUP_CREATE _IOW(BTRFS_IOCTL_MAGIC, 42, \+					struct btrfs_ioctl_qgroup_create_args)+#define BTRFS_IOC_QGROUP_LIMIT _IOR(BTRFS_IOCTL_MAGIC, 43, \+					struct btrfs_ioctl_qgroup_limit_args)+#define BTRFS_IOC_QUOTA_RESCAN _IOW(BTRFS_IOCTL_MAGIC, 44, \+			       struct btrfs_ioctl_quota_rescan_args)+#define BTRFS_IOC_QUOTA_RESCAN_STATUS _IOR(BTRFS_IOCTL_MAGIC, 45, \+			       struct btrfs_ioctl_quota_rescan_args)+#define BTRFS_IOC_QUOTA_RESCAN_WAIT _IO(BTRFS_IOCTL_MAGIC, 46)+#define BTRFS_IOC_GET_FSLABEL _IOR(BTRFS_IOCTL_MAGIC, 49, \+				   char[BTRFS_LABEL_SIZE])+#define BTRFS_IOC_SET_FSLABEL _IOW(BTRFS_IOCTL_MAGIC, 50, \+				   char[BTRFS_LABEL_SIZE])+#define BTRFS_IOC_GET_DEV_STATS _IOWR(BTRFS_IOCTL_MAGIC, 52, \+				      struct btrfs_ioctl_get_dev_stats)+#define BTRFS_IOC_DEV_REPLACE _IOWR(BTRFS_IOCTL_MAGIC, 53, \+				    struct btrfs_ioctl_dev_replace_args)+#define BTRFS_IOC_GET_FEATURES _IOR(BTRFS_IOCTL_MAGIC, 57, \+                                  struct btrfs_ioctl_feature_flags)+#define BTRFS_IOC_SET_FEATURES _IOW(BTRFS_IOCTL_MAGIC, 57, \+                                  struct btrfs_ioctl_feature_flags[2])+#define BTRFS_IOC_GET_SUPPORTED_FEATURES _IOR(BTRFS_IOCTL_MAGIC, 57, \+                                  struct btrfs_ioctl_feature_flags[3])+#ifdef __cplusplus+}+#endif++#endif
+ include/btrfs/kerncompat.h view
@@ -0,0 +1,296 @@+/*+ * Copyright (C) 2007 Oracle.  All rights reserved.+ *+ * This program is free software; you can redistribute it and/or+ * modify it under the terms of the GNU General Public+ * License v2 as published by the Free Software Foundation.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU+ * General Public License for more details.+ *+ * You should have received a copy of the GNU General Public+ * License along with this program; if not, write to the+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,+ * Boston, MA 021110-1307, USA.+ */++#ifndef __KERNCOMPAT+#define __KERNCOMPAT++#include <stdio.h>+#include <stdlib.h>+#include <errno.h>+#include <string.h>+#include <endian.h>+#include <byteswap.h>+#include <assert.h>+#include <stddef.h>+#include <linux/types.h>++#ifndef READ+#define READ 0+#define WRITE 1+#define READA 2+#endif++#define gfp_t int+#define get_cpu_var(p) (p)+#define __get_cpu_var(p) (p)+#define BITS_PER_LONG (__SIZEOF_LONG__ * 8)+#define __GFP_BITS_SHIFT 20+#define __GFP_BITS_MASK ((int)((1 << __GFP_BITS_SHIFT) - 1))+#define GFP_KERNEL 0+#define GFP_NOFS 0+#define __read_mostly+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))++#ifndef ULONG_MAX+#define ULONG_MAX       (~0UL)+#endif++#define BUG() assert(0)+#ifdef __CHECKER__+#define __force    __attribute__((force))+#define __bitwise__ __attribute__((bitwise))+#else+#define __force+#define __bitwise__+#endif++#ifndef __CHECKER__+/*+ * Since we're using primitive definitions from kernel-space, we need to+ * define __KERNEL__ so that system header files know which definitions+ * to use.+ */+#define __KERNEL__+#include <asm/types.h>+typedef __u32 u32;+typedef __u64 u64;+typedef __u16 u16;+typedef __u8 u8;+/*+ * Continuing to define __KERNEL__ breaks others parts of the code, so+ * we can just undefine it now that we have the correct headers...+ */+#undef __KERNEL__+#else+typedef unsigned int u32;+typedef unsigned int __u32;+typedef unsigned long long u64;+typedef unsigned char u8;+typedef unsigned short u16;+#endif+++struct vma_shared { int prio_tree_node; };+struct vm_area_struct {+	unsigned long vm_pgoff;+	unsigned long vm_start;+	unsigned long vm_end;+	struct vma_shared shared;+};++struct page {+	unsigned long index;+};++struct mutex {+	unsigned long lock;+};++#define mutex_init(m)						\+do {								\+	(m)->lock = 1;						\+} while (0)++static inline void mutex_lock(struct mutex *m)+{+	m->lock--;+}++static inline void mutex_unlock(struct mutex *m)+{+	m->lock++;+}++static inline int mutex_is_locked(struct mutex *m)+{+	return (m->lock != 1);+}++#define cond_resched()		do { } while (0)+#define preempt_enable()	do { } while (0)+#define preempt_disable()	do { } while (0)++#define BITOP_MASK(nr)		(1UL << ((nr) % BITS_PER_LONG))+#define BITOP_WORD(nr)		((nr) / BITS_PER_LONG)++#ifndef __attribute_const__+#define __attribute_const__	__attribute__((__const__))+#endif++/**+ * __set_bit - Set a bit in memory+ * @nr: the bit to set+ * @addr: the address to start counting from+ *+ * Unlike set_bit(), this function is non-atomic and may be reordered.+ * If it's called on the same region of memory simultaneously, the effect+ * may be that only one operation succeeds.+ */+static inline void __set_bit(int nr, volatile unsigned long *addr)+{+	unsigned long mask = BITOP_MASK(nr);+	unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr);++	*p  |= mask;+}++static inline void __clear_bit(int nr, volatile unsigned long *addr)+{+	unsigned long mask = BITOP_MASK(nr);+	unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr);++	*p &= ~mask;+}++/**+ * test_bit - Determine whether a bit is set+ * @nr: bit number to test+ * @addr: Address to start counting from+ */+static inline int test_bit(int nr, const volatile unsigned long *addr)+{+	return 1UL & (addr[BITOP_WORD(nr)] >> (nr & (BITS_PER_LONG-1)));+}++/*+ * error pointer+ */+#define MAX_ERRNO	4095+#define IS_ERR_VALUE(x) ((x) >= (unsigned long)-MAX_ERRNO)++static inline void *ERR_PTR(long error)+{+	return (void *) error;+}++static inline long PTR_ERR(const void *ptr)+{+	return (long) ptr;+}++static inline long IS_ERR(const void *ptr)+{+	return IS_ERR_VALUE((unsigned long)ptr);+}++/*+ * max/min macro+ */+#define min(x,y) ({ \+	typeof(x) _x = (x);	\+	typeof(y) _y = (y);	\+	(void) (&_x == &_y);		\+	_x < _y ? _x : _y; })++#define max(x,y) ({ \+	typeof(x) _x = (x);	\+	typeof(y) _y = (y);	\+	(void) (&_x == &_y);		\+	_x > _y ? _x : _y; })++#define min_t(type,x,y) \+	({ type __x = (x); type __y = (y); __x < __y ? __x: __y; })+#define max_t(type,x,y) \+	({ type __x = (x); type __y = (y); __x > __y ? __x: __y; })++/*+ * 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+ * as wide as the result!), and we want to evaluate the macro+ * arguments just once each.+ */+#define __round_mask(x, y) ((__typeof__(x))((y)-1))+#define round_up(x, y) ((((x)-1) | __round_mask(x, y))+1)+#define round_down(x, y) ((x) & ~__round_mask(x, y))++/*+ * printk+ */+#define printk(fmt, args...) fprintf(stderr, fmt, ##args)+#define	KERN_CRIT	""+#define KERN_ERR	""++/*+ * kmalloc/kfree+ */+#define kmalloc(x, y) malloc(x)+#define kzalloc(x, y) calloc(1, x)+#define kstrdup(x, y) strdup(x)+#define kfree(x) free(x)++#define BUG_ON(c) assert(!(c))+#define WARN_ON(c) assert(!(c))+++#define container_of(ptr, type, member) ({                      \+        const typeof( ((type *)0)->member ) *__mptr = (ptr);    \+	        (type *)( (char *)__mptr - offsetof(type,member) );})+#ifdef __CHECKER__+#define __bitwise __bitwise__+#else+#define __bitwise+#endif++typedef u16 __bitwise __le16;+typedef u16 __bitwise __be16;+typedef u32 __bitwise __le32;+typedef u32 __bitwise __be32;+typedef u64 __bitwise __le64;+typedef u64 __bitwise __be64;++/* Macros to generate set/get funcs for the struct fields+ * assume there is a lefoo_to_cpu for every type, so lets make a simple+ * one for u8:+ */+#define le8_to_cpu(v) (v)+#define cpu_to_le8(v) (v)+#define __le8 u8++#if __BYTE_ORDER == __BIG_ENDIAN+#define cpu_to_le64(x) ((__force __le64)(u64)(bswap_64(x)))+#define le64_to_cpu(x) ((__force u64)(__le64)(bswap_64(x)))+#define cpu_to_le32(x) ((__force __le32)(u32)(bswap_32(x)))+#define le32_to_cpu(x) ((__force u32)(__le32)(bswap_32(x)))+#define cpu_to_le16(x) ((__force __le16)(u16)(bswap_16(x)))+#define le16_to_cpu(x) ((__force u16)(__le16)(bswap_16(x)))+#else+#define cpu_to_le64(x) ((__force __le64)(u64)(x))+#define le64_to_cpu(x) ((__force u64)(__le64)(x))+#define cpu_to_le32(x) ((__force __le32)(u32)(x))+#define le32_to_cpu(x) ((__force u32)(__le32)(x))+#define cpu_to_le16(x) ((__force __le16)(u16)(x))+#define le16_to_cpu(x) ((__force u16)(__le16)(x))+#endif++struct __una_u16 { __le16 x; } __attribute__((__packed__));+struct __una_u32 { __le32 x; } __attribute__((__packed__));+struct __una_u64 { __le64 x; } __attribute__((__packed__));++#define get_unaligned_le8(p) (*((u8 *)(p)))+#define put_unaligned_le8(val,p) ((*((u8 *)(p))) = (val))+#define get_unaligned_le16(p) le16_to_cpu(((const struct __una_u16 *)(p))->x)+#define put_unaligned_le16(val,p) (((struct __una_u16 *)(p))->x = cpu_to_le16(val))+#define get_unaligned_le32(p) le32_to_cpu(((const struct __una_u32 *)(p))->x)+#define put_unaligned_le32(val,p) (((struct __una_u32 *)(p))->x = cpu_to_le32(val))+#define get_unaligned_le64(p) le64_to_cpu(((const struct __una_u64 *)(p))->x)+#define put_unaligned_le64(val,p) (((struct __una_u64 *)(p))->x = cpu_to_le64(val))+#endif++#ifndef noinline+#define noinline+#endif
+ include/btrfs/list.h view
@@ -0,0 +1,486 @@+/*+ * Copyright (C) 2007 Oracle.  All rights reserved.+ *+ * This program is free software; you can redistribute it and/or+ * modify it under the terms of the GNU General Public+ * License v2 as published by the Free Software Foundation.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU+ * General Public License for more details.+ *+ * You should have received a copy of the GNU General Public+ * License along with this program; if not, write to the+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,+ * Boston, MA 021110-1307, USA.+ */++#ifndef _LINUX_LIST_H+#define _LINUX_LIST_H++#define LIST_POISON1  ((struct list_head *) 0x00100100)+#define LIST_POISON2  ((struct list_head *) 0x00200200)++/*+ * Simple doubly linked list implementation.+ *+ * Some of the internal functions ("__xxx") are useful when+ * manipulating whole lists rather than single entries, as+ * sometimes we already know the next/prev entries and we can+ * generate better code by using them directly rather than+ * using the generic single-entry routines.+ */++struct list_head {+	struct list_head *next, *prev;+};++#define LIST_HEAD_INIT(name) { &(name), &(name) }++#define LIST_HEAD(name) \+	struct list_head name = LIST_HEAD_INIT(name)++static inline void INIT_LIST_HEAD(struct list_head *list)+{+	list->next = list;+	list->prev = list;+}++/*+ * Insert a new entry between two known consecutive entries.+ *+ * This is only for internal list manipulation where we know+ * the prev/next entries already!+ */+#ifndef CONFIG_DEBUG_LIST+static inline void __list_add(struct list_head *xnew,+			      struct list_head *prev,+			      struct list_head *next)+{+	next->prev = xnew;+	xnew->next = next;+	xnew->prev = prev;+	prev->next = xnew;+}+#else+extern void __list_add(struct list_head *xnew,+			      struct list_head *prev,+			      struct list_head *next);+#endif++/**+ * list_add - add a new entry+ * @new: new entry to be added+ * @head: list head to add it after+ *+ * Insert a new entry after the specified head.+ * This is good for implementing stacks.+ */+#ifndef CONFIG_DEBUG_LIST+static inline void list_add(struct list_head *xnew, struct list_head *head)+{+	__list_add(xnew, head, head->next);+}+#else+extern void list_add(struct list_head *xnew, struct list_head *head);+#endif+++/**+ * list_add_tail - add a new entry+ * @new: new entry to be added+ * @head: list head to add it before+ *+ * Insert a new entry before the specified head.+ * This is useful for implementing queues.+ */+static inline void list_add_tail(struct list_head *xnew, struct list_head *head)+{+	__list_add(xnew, head->prev, head);+}++/*+ * Delete a list entry by making the prev/next entries+ * point to each other.+ *+ * This is only for internal list manipulation where we know+ * the prev/next entries already!+ */+static inline void __list_del(struct list_head * prev, struct list_head * next)+{+	next->prev = prev;+	prev->next = next;+}++/**+ * list_del - deletes entry from list.+ * @entry: the element to delete from the list.+ * Note: list_empty on entry does not return true after this, the entry is+ * in an undefined state.+ */+#ifndef CONFIG_DEBUG_LIST+static inline void list_del(struct list_head *entry)+{+	__list_del(entry->prev, entry->next);+	entry->next = LIST_POISON1;+	entry->prev = LIST_POISON2;+}+#else+extern void list_del(struct list_head *entry);+#endif++/**+ * list_replace - replace old entry by new one+ * @old : the element to be replaced+ * @new : the new element to insert+ * Note: if 'old' was empty, it will be overwritten.+ */+static inline void list_replace(struct list_head *old,+				struct list_head *xnew)+{+	xnew->next = old->next;+	xnew->next->prev = xnew;+	xnew->prev = old->prev;+	xnew->prev->next = xnew;+}++static inline void list_replace_init(struct list_head *old,+					struct list_head *xnew)+{+	list_replace(old, xnew);+	INIT_LIST_HEAD(old);+}+/**+ * list_del_init - deletes entry from list and reinitialize it.+ * @entry: the element to delete from the list.+ */+static inline void list_del_init(struct list_head *entry)+{+	__list_del(entry->prev, entry->next);+	INIT_LIST_HEAD(entry);+}++/**+ * list_move - delete from one list and add as another's head+ * @list: the entry to move+ * @head: the head that will precede our entry+ */+static inline void list_move(struct list_head *list, struct list_head *head)+{+        __list_del(list->prev, list->next);+        list_add(list, head);+}++/**+ * list_move_tail - delete from one list and add as another's tail+ * @list: the entry to move+ * @head: the head that will follow our entry+ */+static inline void list_move_tail(struct list_head *list,+				  struct list_head *head)+{+        __list_del(list->prev, list->next);+        list_add_tail(list, head);+}++/**+ * list_is_last - tests whether @list is the last entry in list @head+ * @list: the entry to test+ * @head: the head of the list+ */+static inline int list_is_last(const struct list_head *list,+				const struct list_head *head)+{+	return list->next == head;+}++/**+ * list_empty - tests whether a list is empty+ * @head: the list to test.+ */+static inline int list_empty(const struct list_head *head)+{+	return head->next == head;+}++/**+ * list_empty_careful - tests whether a list is empty and not being modified+ * @head: the list to test+ *+ * Description:+ * tests whether a list is empty _and_ checks that no other CPU might be+ * in the process of modifying either member (next or prev)+ *+ * NOTE: using list_empty_careful() without synchronization+ * can only be safe if the only activity that can happen+ * to the list entry is list_del_init(). Eg. it cannot be used+ * if another CPU could re-list_add() it.+ */+static inline int list_empty_careful(const struct list_head *head)+{+	struct list_head *next = head->next;+	return (next == head) && (next == head->prev);+}++static inline void __list_splice(const struct list_head *list,+				 struct list_head *prev,+				 struct list_head *next)+{+	struct list_head *first = list->next;+	struct list_head *last = list->prev;++	first->prev = prev;+	prev->next = first;++	last->next = next;+	next->prev = last;+}++/**+ * list_splice - join two lists+ * @list: the new list to add.+ * @head: the place to add it in the first list.+ */+static inline void list_splice(struct list_head *list, struct list_head *head)+{+	if (!list_empty(list))+		__list_splice(list, head, head->next);+}++/**+ * list_splice_tail - join two lists, each list being a queue+ * @list: the new list to add.+ * @head: the place to add it in the first list.+ */+static inline void list_splice_tail(struct list_head *list,+				struct list_head *head)+{+	if (!list_empty(list))+		__list_splice(list, head->prev, head);+}++/**+ * list_splice_init - join two lists and reinitialise the emptied list.+ * @list: the new list to add.+ * @head: the place to add it in the first list.+ *+ * The list at @list is reinitialised+ */+static inline void list_splice_init(struct list_head *list,+				    struct list_head *head)+{+	if (!list_empty(list)) {+		__list_splice(list, head, head->next);+		INIT_LIST_HEAD(list);+	}+}++/**+ * list_splice_tail_init - join two lists and reinitialise the emptied list+ * @list: the new list to add.+ * @head: the place to add it in the first list.+ *+ * Each of the lists is a queue.+ * The list at @list is reinitialised+ */+static inline void list_splice_tail_init(struct list_head *list,+					 struct list_head *head)+{+	if (!list_empty(list)) {+		__list_splice(list, head->prev, head);+		INIT_LIST_HEAD(list);+	}+}++/**+ * list_entry - get the struct for this entry+ * @ptr:	the &struct list_head pointer.+ * @type:	the type of the struct this is embedded in.+ * @member:	the name of the list_struct within the struct.+ */+#define list_entry(ptr, type, member) \+	container_of(ptr, type, member)++/**+ * list_first_entry - get the first element from a list+ * @ptr:	the list head to take the element from.+ * @type:	the type of the struct this is embedded in.+ * @member:	the name of the list_struct within the struct.+ *+ * Note, that list is expected to be not empty.+ */+#define list_first_entry(ptr, type, member) \+	list_entry((ptr)->next, type, member)++/**+ * list_next_entry - get the next element from a list+ * @ptr:	the list head to take the element from.+ * @member:	the name of the list_struct within the struct.+ *+ * Note, that next is expected to be not null.+ */+#define list_next_entry(ptr, member) \+	list_entry((ptr)->member.next, typeof(*ptr), member)++/**+ * list_for_each	-	iterate over a list+ * @pos:	the &struct list_head to use as a loop cursor.+ * @head:	the head for your list.+ */+#define list_for_each(pos, head) \+	for (pos = (head)->next; pos != (head); \+        	pos = pos->next)++/**+ * __list_for_each	-	iterate over a list+ * @pos:	the &struct list_head to use as a loop cursor.+ * @head:	the head for your list.+ *+ * This variant differs from list_for_each() in that it's the+ * simplest possible list iteration code, no prefetching is done.+ * Use this for code that knows the list to be very short (empty+ * or 1 entry) most of the time.+ */+#define __list_for_each(pos, head) \+	for (pos = (head)->next; pos != (head); pos = pos->next)++/**+ * list_for_each_prev	-	iterate over a list backwards+ * @pos:	the &struct list_head to use as a loop cursor.+ * @head:	the head for your list.+ */+#define list_for_each_prev(pos, head) \+	for (pos = (head)->prev; pos != (head); \+        	pos = pos->prev)++/**+ * list_for_each_safe - iterate over a list safe against removal of list entry+ * @pos:	the &struct list_head to use as a loop cursor.+ * @n:		another &struct list_head to use as temporary storage+ * @head:	the head for your list.+ */+#define list_for_each_safe(pos, n, head) \+	for (pos = (head)->next, n = pos->next; pos != (head); \+		pos = n, n = pos->next)++/**+ * list_for_each_entry	-	iterate over list of given type+ * @pos:	the type * to use as a loop cursor.+ * @head:	the head for your list.+ * @member:	the name of the list_struct within the struct.+ */+#define list_for_each_entry(pos, head, member)				\+	for (pos = list_entry((head)->next, typeof(*pos), member);	\+	     &pos->member != (head); 	\+	     pos = list_entry(pos->member.next, typeof(*pos), member))++/**+ * list_for_each_entry_reverse - iterate backwards over list of given type.+ * @pos:	the type * to use as a loop cursor.+ * @head:	the head for your list.+ * @member:	the name of the list_struct within the struct.+ */+#define list_for_each_entry_reverse(pos, head, member)			\+	for (pos = list_entry((head)->prev, typeof(*pos), member);	\+	     &pos->member != (head); 	\+	     pos = list_entry(pos->member.prev, typeof(*pos), member))++/**+ * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue+ * @pos:	the type * to use as a start point+ * @head:	the head of the list+ * @member:	the name of the list_struct within the struct.+ *+ * Prepares a pos entry for use as a start point in list_for_each_entry_continue.+ */+#define list_prepare_entry(pos, head, member) \+	((pos) ? : list_entry(head, typeof(*pos), member))++/**+ * list_for_each_entry_continue - continue iteration over list of given type+ * @pos:	the type * to use as a loop cursor.+ * @head:	the head for your list.+ * @member:	the name of the list_struct within the struct.+ *+ * Continue to iterate over list of given type, continuing after+ * the current position.+ */+#define list_for_each_entry_continue(pos, head, member) 		\+	for (pos = list_entry(pos->member.next, typeof(*pos), member);	\+	     &pos->member != (head);	\+	     pos = list_entry(pos->member.next, typeof(*pos), member))++/**+ * list_for_each_entry_from - iterate over list of given type from the current point+ * @pos:	the type * to use as a loop cursor.+ * @head:	the head for your list.+ * @member:	the name of the list_struct within the struct.+ *+ * Iterate over list of given type, continuing from current position.+ */+#define list_for_each_entry_from(pos, head, member) 			\+	for (; &pos->member != (head);	\+	     pos = list_entry(pos->member.next, typeof(*pos), member))++/**+ * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry+ * @pos:	the type * to use as a loop cursor.+ * @n:		another type * to use as temporary storage+ * @head:	the head for your list.+ * @member:	the name of the list_struct within the struct.+ */+#define list_for_each_entry_safe(pos, n, head, member)			\+	for (pos = list_entry((head)->next, typeof(*pos), member),	\+		n = list_entry(pos->member.next, typeof(*pos), member);	\+	     &pos->member != (head); 					\+	     pos = n, n = list_entry(n->member.next, typeof(*n), member))++/**+ * list_for_each_entry_safe_continue+ * @pos:	the type * to use as a loop cursor.+ * @n:		another type * to use as temporary storage+ * @head:	the head for your list.+ * @member:	the name of the list_struct within the struct.+ *+ * Iterate over list of given type, continuing after current point,+ * safe against removal of list entry.+ */+#define list_for_each_entry_safe_continue(pos, n, head, member) 		\+	for (pos = list_entry(pos->member.next, typeof(*pos), member), 		\+		n = list_entry(pos->member.next, typeof(*pos), member);		\+	     &pos->member != (head);						\+	     pos = n, n = list_entry(n->member.next, typeof(*n), member))++/**+ * list_for_each_entry_safe_from+ * @pos:	the type * to use as a loop cursor.+ * @n:		another type * to use as temporary storage+ * @head:	the head for your list.+ * @member:	the name of the list_struct within the struct.+ *+ * Iterate over list of given type from current point, safe against+ * removal of list entry.+ */+#define list_for_each_entry_safe_from(pos, n, head, member) 			\+	for (n = list_entry(pos->member.next, typeof(*pos), member);		\+	     &pos->member != (head);						\+	     pos = n, n = list_entry(n->member.next, typeof(*n), member))++/**+ * list_for_each_entry_safe_reverse+ * @pos:	the type * to use as a loop cursor.+ * @n:		another type * to use as temporary storage+ * @head:	the head for your list.+ * @member:	the name of the list_struct within the struct.+ *+ * Iterate backwards over list of given type, safe against removal+ * of list entry.+ */+#define list_for_each_entry_safe_reverse(pos, n, head, member)		\+	for (pos = list_entry((head)->prev, typeof(*pos), member),	\+		n = list_entry(pos->member.prev, typeof(*pos), member);	\+	     &pos->member != (head); 					\+	     pos = n, n = list_entry(n->member.prev, typeof(*n), member))++#endif
+ include/btrfs/radix-tree.h view
@@ -0,0 +1,97 @@+/*+ * Copyright (C) 2007 Oracle.  All rights reserved.+ *+ * This program is free software; you can redistribute it and/or+ * modify it under the terms of the GNU General Public+ * License v2 as published by the Free Software Foundation.+ *+ * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU+ * General Public License for more details.+ *+ * You should have received a copy of the GNU General Public+ * License along with this program; if not, write to the+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,+ * Boston, MA 021110-1307, USA.+ */++/*+ * Copyright (C) 2001 Momchil Velikov+ * Portions Copyright (C) 2001 Christoph Hellwig+ *+ * This program is free software; you can redistribute it and/or+ * modify it under the terms of the GNU General Public License as+ * published by the Free Software Foundation; either version 2, or (at+ * your option) any later version.+ * + * This program is distributed in the hope that it will be useful, but+ * WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU+ * General Public License for more details.+ * + * You should have received a copy of the GNU General Public License+ * along with this program; if not, write to the Free Software+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.+ */+#ifndef _LINUX_RADIX_TREE_H+#define _LINUX_RADIX_TREE_H++#if BTRFS_FLAT_INCLUDES+#include "kerncompat.h"+#else+#include <btrfs/kerncompat.h>+#endif /* BTRFS_FLAT_INCLUDES */++#define RADIX_TREE_MAX_TAGS 2++/* root tags are stored in gfp_mask, shifted by __GFP_BITS_SHIFT */+struct radix_tree_root {+	unsigned int		height;+	gfp_t			gfp_mask;+	struct radix_tree_node	*rnode;+};++#define RADIX_TREE_INIT(mask)	{					\+	.height = 0,							\+	.gfp_mask = (mask),						\+	.rnode = NULL,							\+}++#define RADIX_TREE(name, mask) \+	struct radix_tree_root name = RADIX_TREE_INIT(mask)++#define INIT_RADIX_TREE(root, mask)					\+do {									\+	(root)->height = 0;						\+	(root)->gfp_mask = (mask);					\+	(root)->rnode = NULL;						\+} while (0)++int radix_tree_insert(struct radix_tree_root *, unsigned long, void *);+void *radix_tree_lookup(struct radix_tree_root *, unsigned long);+void **radix_tree_lookup_slot(struct radix_tree_root *, unsigned long);+void *radix_tree_delete(struct radix_tree_root *, unsigned long);+unsigned int+radix_tree_gang_lookup(struct radix_tree_root *root, void **results,+			unsigned long first_index, unsigned int max_items);+int radix_tree_preload(gfp_t gfp_mask);+void radix_tree_init(void);+void *radix_tree_tag_set(struct radix_tree_root *root,+			unsigned long index, unsigned int tag);+void *radix_tree_tag_clear(struct radix_tree_root *root,+			unsigned long index, unsigned int tag);+int radix_tree_tag_get(struct radix_tree_root *root,+			unsigned long index, unsigned int tag);+unsigned int+radix_tree_gang_lookup_tag(struct radix_tree_root *root, void **results,+		unsigned long first_index, unsigned int max_items,+		unsigned int tag);+int radix_tree_tagged(struct radix_tree_root *root, unsigned int tag);++static inline void radix_tree_preload_end(void)+{+	preempt_enable();+}++#endif /* _LINUX_RADIX_TREE_H */
+ include/btrfs/rbtree.h view
@@ -0,0 +1,182 @@+/*+  Red Black Trees+  (C) 1999  Andrea Arcangeli <andrea@suse.de>+  +  This program is free software; you can redistribute it and/or modify+  it under the terms of the GNU General Public License as published by+  the Free Software Foundation; either version 2 of the License, or+  (at your option) any later version.++  This program is distributed in the hope that it will be useful,+  but WITHOUT ANY WARRANTY; without even the implied warranty of+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+  GNU General Public License for more details.++  You should have received a copy of the GNU General Public License+  along with this program; if not, write to the Free Software+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA++  linux/include/linux/rbtree.h++  To use rbtrees you'll have to implement your own insert and search cores.+  This will avoid us to use callbacks and to drop drammatically performances.+  I know it's not the cleaner way,  but in C (not in C++) to get+  performances and genericity...++  Some example of insert and search follows here. The search is a plain+  normal search over an ordered tree. The insert instead must be implemented+  int two steps: as first thing the code must insert the element in+  order as a red leaf in the tree, then the support library function+  rb_insert_color() must be called. Such function will do the+  not trivial work to rebalance the rbtree if necessary.++-----------------------------------------------------------------------+static inline struct page * rb_search_page_cache(struct inode * inode,+						 unsigned long offset)+{+	struct rb_node * n = inode->i_rb_page_cache.rb_node;+	struct page * page;++	while (n)+	{+		page = rb_entry(n, struct page, rb_page_cache);++		if (offset < page->offset)+			n = n->rb_left;+		else if (offset > page->offset)+			n = n->rb_right;+		else+			return page;+	}+	return NULL;+}++static inline struct page * __rb_insert_page_cache(struct inode * inode,+						   unsigned long offset,+						   struct rb_node * node)+{+	struct rb_node ** p = &inode->i_rb_page_cache.rb_node;+	struct rb_node * parent = NULL;+	struct page * page;++	while (*p)+	{+		parent = *p;+		page = rb_entry(parent, struct page, rb_page_cache);++		if (offset < page->offset)+			p = &(*p)->rb_left;+		else if (offset > page->offset)+			p = &(*p)->rb_right;+		else+			return page;+	}++	rb_link_node(node, parent, p);++	return NULL;+}++static inline struct page * rb_insert_page_cache(struct inode * inode,+						 unsigned long offset,+						 struct rb_node * node)+{+	struct page * ret;+	if ((ret = __rb_insert_page_cache(inode, offset, node)))+		goto out;+	rb_insert_color(node, &inode->i_rb_page_cache);+ out:+	return ret;+}+-----------------------------------------------------------------------+*/++#ifndef	_LINUX_RBTREE_H+#define	_LINUX_RBTREE_H+#if BTRFS_FLAT_INCLUDES+#include "kerncompat.h"+#else+#include <btrfs/kerncompat.h>+#endif /* BTRFS_FLAT_INCLUDES */+struct rb_node+{+	unsigned long  rb_parent_color;+#define	RB_RED		0+#define	RB_BLACK	1+	struct rb_node *rb_right;+	struct rb_node *rb_left;+} __attribute__((aligned(sizeof(long))));+    /* The alignment might seem pointless, but allegedly CRIS needs it */++struct rb_root+{+	struct rb_node *rb_node;+};++#define rb_parent(r)   ((struct rb_node *)((r)->rb_parent_color & ~3))+#define rb_color(r)   ((r)->rb_parent_color & 1)+#define rb_is_red(r)   (!rb_color(r))+#define rb_is_black(r) rb_color(r)+#define rb_set_red(r)  do { (r)->rb_parent_color &= ~1; } while (0)+#define rb_set_black(r)  do { (r)->rb_parent_color |= 1; } while (0)++static inline void rb_set_parent(struct rb_node *rb, struct rb_node *p)+{+	rb->rb_parent_color = (rb->rb_parent_color & 3) | (unsigned long)p;+}+static inline void rb_set_color(struct rb_node *rb, int color)+{+	rb->rb_parent_color = (rb->rb_parent_color & ~1) | color;+}++#define RB_ROOT	(struct rb_root) { NULL, }+#define	rb_entry(ptr, type, member) container_of(ptr, type, member)++#define RB_EMPTY_ROOT(root)	((root)->rb_node == NULL)+#define RB_EMPTY_NODE(node)	(rb_parent(node) == node)+#define RB_CLEAR_NODE(node)	(rb_set_parent(node, node))++extern void rb_insert_color(struct rb_node *, struct rb_root *);+extern void rb_erase(struct rb_node *, struct rb_root *);++/* Find logical next and previous nodes in a tree */+extern struct rb_node *rb_next(struct rb_node *);+extern struct rb_node *rb_prev(struct rb_node *);+extern struct rb_node *rb_first(struct rb_root *);+extern struct rb_node *rb_last(struct rb_root *);++/* Fast replacement of a single node without remove/rebalance/add/rebalance */+extern void rb_replace_node(struct rb_node *victim, struct rb_node *xnew,+			    struct rb_root *root);++static inline void rb_link_node(struct rb_node * node, struct rb_node * parent,+				struct rb_node ** rb_link)+{+	node->rb_parent_color = (unsigned long )parent;+	node->rb_left = node->rb_right = NULL;++	*rb_link = node;+}++/* The common insert/search/free functions */+typedef int (*rb_compare_nodes)(struct rb_node *node1, struct rb_node *node2);+typedef int (*rb_compare_keys)(struct rb_node *node, void *key);+typedef void (*rb_free_node)(struct rb_node *node);++int rb_insert(struct rb_root *root, struct rb_node *node,+	      rb_compare_nodes comp);+/*+ * In some cases, we need return the next node if we don't find the node we+ * specify. At this time, we can use next_ret.+ */+struct rb_node *rb_search(struct rb_root *root, void *key, rb_compare_keys comp,+			  struct rb_node **next_ret);+void rb_free_nodes(struct rb_root *root, rb_free_node free_node);++#define FREE_RB_BASED_TREE(name, free_func)		\+static void free_##name##_tree(struct rb_root *root)	\+{							\+	rb_free_nodes(root, free_func);			\+}++#endif	/* _LINUX_RBTREE_H */