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 +62/−0
- LICENSE +30/−0
- Setup.hs +40/−0
- System/Linux/Btrfs.hsc +1058/−0
- System/Linux/Btrfs/FilePathLike.hs +87/−0
- System/Linux/Btrfs/Time.hsc +27/−0
- System/Linux/Btrfs/UUID.hs +62/−0
- btrfs.cabal +82/−0
- examples/btrfs-clone-range.hs +9/−0
- examples/btrfs-defrag.hs +41/−0
- examples/btrfs-list-subvols.hs +15/−0
- include/btrfs/ctree.h +2385/−0
- include/btrfs/extent-cache.h +81/−0
- include/btrfs/extent_io.h +137/−0
- include/btrfs/ioctl.h +609/−0
- include/btrfs/kerncompat.h +296/−0
- include/btrfs/list.h +486/−0
- include/btrfs/radix-tree.h +97/−0
- include/btrfs/rbtree.h +182/−0
+ 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 */