root/src/add-ons/kernel/file_systems/bfs/Volume.h
/*
 * Copyright 2001-2012, Axel Dörfler, axeld@pinc-software.de.
 * This file may be used under the terms of the MIT License.
 */
#ifndef VOLUME_H
#define VOLUME_H


#include "system_dependencies.h"

#include "bfs.h"
#include "BlockAllocator.h"


class CheckVisitor;
class Journal;
class Inode;
class Query;


enum volume_flags {
        VOLUME_READ_ONLY        = 0x0001
};

enum volume_initialize_flags {
        VOLUME_NO_INDICES       = 0x0001,
};

typedef DoublyLinkedList<Inode> InodeList;


class Volume {
public:
                                                        Volume(fs_volume* volume);
                                                        ~Volume();

                        status_t                Mount(const char* device, uint32 flags);
                        status_t                Unmount();
                        status_t                Initialize(int fd, const char* name,
                                                                uint32 blockSize, uint32 flags);

                        bool                    IsInitializing() const { return fVolume == NULL; }

                        bool                    IsValidSuperBlock() const;
                        bool                    IsValidInodeBlock(off_t block) const;
                        bool                    IsReadOnly() const;
                        void                    Panic();
                        mutex&                  Lock();

                        block_run               Root() const { return fSuperBlock.root_dir; }
                        Inode*                  RootNode() const { return fRootNode; }
                        block_run               Indices() const { return fSuperBlock.indices; }
                        Inode*                  IndicesNode() const { return fIndicesNode; }
                        block_run               Log() const { return fSuperBlock.log_blocks; }
                        vint32&                 LogStart() { return fLogStart; }
                        vint32&                 LogEnd() { return fLogEnd; }
                        int                             Device() const { return fDevice; }

                        dev_t                   ID() const { return fVolume ? fVolume->id : -1; }
                        fs_volume*              FSVolume() const { return fVolume; }
                        const char*             Name() const { return fSuperBlock.name; }

                        off_t                   NumBlocks() const
                                                                { return fSuperBlock.NumBlocks(); }
                        off_t                   UsedBlocks() const
                                                                { return fSuperBlock.UsedBlocks(); }
                        off_t                   FreeBlocks() const
                                                                { return NumBlocks() - UsedBlocks(); }
                        off_t                   NumBitmapBlocks() const
                                                                { return (NumBlocks() + fBlockSize * 8 - 1)
                                                                        / (fBlockSize * 8); }

                        uint32                  DeviceBlockSize() const { return fDeviceBlockSize; }
                        uint32                  BlockSize() const { return fBlockSize; }
                        uint32                  BlockShift() const { return fBlockShift; }
                        uint32                  InodeSize() const
                                                                { return fSuperBlock.InodeSize(); }
                        uint32                  AllocationGroups() const
                                                                { return fSuperBlock.AllocationGroups(); }
                        uint32                  AllocationGroupShift() const
                                                                { return fAllocationGroupShift; }
                        disk_super_block& SuperBlock() { return fSuperBlock; }

                        off_t                   ToOffset(block_run run) const
                                                                { return ToBlock(run) << BlockShift(); }
                        off_t                   ToBlock(block_run run) const
                                                                { return ((((off_t)run.AllocationGroup())
                                                                                << AllocationGroupShift())
                                                                        | (off_t)run.Start()); }
                        block_run               ToBlockRun(off_t block) const;
                        status_t                ValidateBlockRun(block_run run);

                        off_t                   ToVnode(block_run run) const
                                                                { return ToBlock(run); }
                        off_t                   ToVnode(off_t block) const { return block; }
                        off_t                   VnodeToBlock(ino_t id) const { return (off_t)id; }

                        status_t                CreateIndicesRoot(Transaction& transaction);

                        status_t                CreateVolumeID(Transaction& transaction);

                        InodeList&              RemovedInodes();

                        // block bitmap
                        BlockAllocator& Allocator();
                        status_t                AllocateForInode(Transaction& transaction,
                                                                const Inode* parent, mode_t type,
                                                                block_run& run);
                        status_t                AllocateForInode(Transaction& transaction,
                                                                const block_run* parent, mode_t type,
                                                                block_run& run);
                        status_t                Allocate(Transaction& transaction, Inode* inode,
                                                                off_t numBlocks, block_run& run,
                                                                uint16 minimum = 1);
                        status_t                Free(Transaction& transaction, block_run run);
                        void                    SetCheckingThread(thread_id thread)
                                                                { fCheckingThread = thread; }
                        bool                    IsCheckingThread() const
                                                                { return find_thread(NULL) == fCheckingThread; }
                        status_t                CreateCheckVisitor();
                        void                    DeleteCheckVisitor();
                        ::CheckVisitor* CheckVisitor() { return fCheckVisitor; }

                        // cache access
                        status_t                WriteSuperBlock();
                        status_t                FlushDevice();

                        // queries
                        void                    UpdateLiveQueries(Inode* inode,
                                                                const char* attribute, int32 type,
                                                                const uint8* oldKey, size_t oldLength,
                                                                const uint8* newKey, size_t newLength);
                        void                    UpdateLiveQueriesRenameMove(Inode* inode,
                                                                ino_t oldDirectoryID, const char* oldName,
                                                                ino_t newDirectoryID, const char* newName);

                        bool                    CheckForLiveQuery(const char* attribute);
                        void                    AddQuery(Query* query);
                        void                    RemoveQuery(Query* query);

                        status_t                Sync();
                        Journal*                GetJournal(off_t refBlock) const;

                        void*                   BlockCache() { return fBlockCache; }

        static  status_t                CheckSuperBlock(const uint8* data,
                                                                uint32* _offset = NULL);
        static  status_t                Identify(int fd, disk_super_block* superBlock);

private:
                        status_t                _EraseUnusedBootBlock();

protected:
                        fs_volume*              fVolume;
                        int                             fDevice;
                        disk_super_block fSuperBlock;

                        uint32                  fDeviceBlockSize;
                        uint32                  fBlockSize;
                        uint32                  fBlockShift;
                        uint32                  fAllocationGroupShift;

                        BlockAllocator  fBlockAllocator;
                        mutex                   fLock;
                        Journal*                fJournal;
                        vint32                  fLogStart;
                        vint32                  fLogEnd;

                        Inode*                  fRootNode;
                        Inode*                  fIndicesNode;

                        vint32                  fDirtyCachedBlocks;

                        mutex                   fQueryLock;
                        DoublyLinkedList<Query> fQueries;

                        uint32                  fFlags;

                        void*                   fBlockCache;
                        thread_id               fCheckingThread;
                        ::CheckVisitor* fCheckVisitor;

                        InodeList               fRemovedInodes;
};


// inline functions

inline bool
Volume::IsReadOnly() const
{
         return fFlags & VOLUME_READ_ONLY;
}


inline mutex&
Volume::Lock()
{
         return fLock;
}


inline BlockAllocator&
Volume::Allocator()
{
         return fBlockAllocator;
}


inline status_t
Volume::AllocateForInode(Transaction& transaction, const block_run* parent,
        mode_t type, block_run& run)
{
        return fBlockAllocator.AllocateForInode(transaction, parent, type, run);
}


inline status_t
Volume::Allocate(Transaction& transaction, Inode* inode, off_t numBlocks,
        block_run& run, uint16 minimum)
{
        return fBlockAllocator.Allocate(transaction, inode, numBlocks, run,
                minimum);
}


inline status_t
Volume::Free(Transaction& transaction, block_run run)
{
        return fBlockAllocator.Free(transaction, run);
}


inline status_t
Volume::FlushDevice()
{
        return block_cache_sync(fBlockCache);
}


inline Journal*
Volume::GetJournal(off_t /*refBlock*/) const
{
         return fJournal;
}


#endif  // VOLUME_H