1/*
2 * Copyright 2001-2012, Axel D��rfler, axeld@pinc-software.de.
3 * This file may be used under the terms of the MIT License.
4 */
5#ifndef VOLUME_H
6#define VOLUME_H
7
8
9#include "system_dependencies.h"
10
11#include "bfs.h"
12#include "BlockAllocator.h"
13
14
15class CheckVisitor;
16class Journal;
17class Inode;
18class Query;
19
20
21enum volume_flags {
22	VOLUME_READ_ONLY	= 0x0001
23};
24
25enum volume_initialize_flags {
26	VOLUME_NO_INDICES	= 0x0001,
27};
28
29typedef DoublyLinkedList<Inode> InodeList;
30
31
32class Volume {
33public:
34							Volume(fs_volume* volume);
35							~Volume();
36
37			status_t		Mount(const char* device, uint32 flags);
38			status_t		Unmount();
39			status_t		Initialize(int fd, const char* name,
40								uint32 blockSize, uint32 flags);
41
42			bool			IsInitializing() const { return fVolume == NULL; }
43
44			bool			IsValidSuperBlock() const;
45			bool			IsValidInodeBlock(off_t block) const;
46			bool			IsReadOnly() const;
47			void			Panic();
48			mutex&			Lock();
49
50			block_run		Root() const { return fSuperBlock.root_dir; }
51			Inode*			RootNode() const { return fRootNode; }
52			block_run		Indices() const { return fSuperBlock.indices; }
53			Inode*			IndicesNode() const { return fIndicesNode; }
54			block_run		Log() const { return fSuperBlock.log_blocks; }
55			vint32&			LogStart() { return fLogStart; }
56			vint32&			LogEnd() { return fLogEnd; }
57			int				Device() const { return fDevice; }
58
59			dev_t			ID() const { return fVolume ? fVolume->id : -1; }
60			fs_volume*		FSVolume() const { return fVolume; }
61			const char*		Name() const { return fSuperBlock.name; }
62
63			off_t			NumBlocks() const
64								{ return fSuperBlock.NumBlocks(); }
65			off_t			UsedBlocks() const
66								{ return fSuperBlock.UsedBlocks(); }
67			off_t			FreeBlocks() const
68								{ return NumBlocks() - UsedBlocks(); }
69			off_t			NumBitmapBlocks() const
70								{ return (NumBlocks() + fBlockSize * 8 - 1)
71									/ (fBlockSize * 8); }
72
73			uint32			DeviceBlockSize() const { return fDeviceBlockSize; }
74			uint32			BlockSize() const { return fBlockSize; }
75			uint32			BlockShift() const { return fBlockShift; }
76			uint32			InodeSize() const
77								{ return fSuperBlock.InodeSize(); }
78			uint32			AllocationGroups() const
79								{ return fSuperBlock.AllocationGroups(); }
80			uint32			AllocationGroupShift() const
81								{ return fAllocationGroupShift; }
82			disk_super_block& SuperBlock() { return fSuperBlock; }
83
84			off_t			ToOffset(block_run run) const
85								{ return ToBlock(run) << BlockShift(); }
86			off_t			ToBlock(block_run run) const
87								{ return ((((off_t)run.AllocationGroup())
88										<< AllocationGroupShift())
89									| (off_t)run.Start()); }
90			block_run		ToBlockRun(off_t block) const;
91			status_t		ValidateBlockRun(block_run run);
92
93			off_t			ToVnode(block_run run) const
94								{ return ToBlock(run); }
95			off_t			ToVnode(off_t block) const { return block; }
96			off_t			VnodeToBlock(ino_t id) const { return (off_t)id; }
97
98			status_t		CreateIndicesRoot(Transaction& transaction);
99
100			status_t		CreateVolumeID(Transaction& transaction);
101
102			InodeList&		RemovedInodes() { return fRemovedInodes; }
103				// This list is guarded by the transaction lock
104
105			// block bitmap
106			BlockAllocator&	Allocator();
107			status_t		AllocateForInode(Transaction& transaction,
108								const Inode* parent, mode_t type,
109								block_run& run);
110			status_t		AllocateForInode(Transaction& transaction,
111								const block_run* parent, mode_t type,
112								block_run& run);
113			status_t		Allocate(Transaction& transaction, Inode* inode,
114								off_t numBlocks, block_run& run,
115								uint16 minimum = 1);
116			status_t		Free(Transaction& transaction, block_run run);
117			void			SetCheckingThread(thread_id thread)
118								{ fCheckingThread = thread; }
119			bool			IsCheckingThread() const
120								{ return find_thread(NULL) == fCheckingThread; }
121			status_t		CreateCheckVisitor();
122			void			DeleteCheckVisitor();
123			::CheckVisitor*	CheckVisitor() { return fCheckVisitor; }
124
125			// cache access
126			status_t		WriteSuperBlock();
127			status_t		FlushDevice();
128
129			// queries
130			void			UpdateLiveQueries(Inode* inode,
131								const char* attribute, int32 type,
132								const uint8* oldKey, size_t oldLength,
133								const uint8* newKey, size_t newLength);
134			void			UpdateLiveQueriesRenameMove(Inode* inode,
135								ino_t oldDirectoryID, const char* oldName,
136								ino_t newDirectoryID, const char* newName);
137
138			bool			CheckForLiveQuery(const char* attribute);
139			void			AddQuery(Query* query);
140			void			RemoveQuery(Query* query);
141
142			status_t		Sync();
143			Journal*		GetJournal(off_t refBlock) const;
144
145			void*			BlockCache() { return fBlockCache; }
146
147	static	status_t		CheckSuperBlock(const uint8* data,
148								uint32* _offset = NULL);
149	static	status_t		Identify(int fd, disk_super_block* superBlock);
150
151private:
152			status_t		_EraseUnusedBootBlock();
153
154protected:
155			fs_volume*		fVolume;
156			int				fDevice;
157			disk_super_block fSuperBlock;
158
159			uint32			fDeviceBlockSize;
160			uint32			fBlockSize;
161			uint32			fBlockShift;
162			uint32			fAllocationGroupShift;
163
164			BlockAllocator	fBlockAllocator;
165			mutex			fLock;
166			Journal*		fJournal;
167			vint32			fLogStart;
168			vint32			fLogEnd;
169
170			Inode*			fRootNode;
171			Inode*			fIndicesNode;
172
173			vint32			fDirtyCachedBlocks;
174
175			mutex			fQueryLock;
176			SinglyLinkedList<Query> fQueries;
177
178			uint32			fFlags;
179
180			void*			fBlockCache;
181			thread_id		fCheckingThread;
182			::CheckVisitor*	fCheckVisitor;
183
184			InodeList		fRemovedInodes;
185};
186
187
188// inline functions
189
190inline bool
191Volume::IsReadOnly() const
192{
193	 return fFlags & VOLUME_READ_ONLY;
194}
195
196
197inline mutex&
198Volume::Lock()
199{
200	 return fLock;
201}
202
203
204inline BlockAllocator&
205Volume::Allocator()
206{
207	 return fBlockAllocator;
208}
209
210
211inline status_t
212Volume::AllocateForInode(Transaction& transaction, const block_run* parent,
213	mode_t type, block_run& run)
214{
215	return fBlockAllocator.AllocateForInode(transaction, parent, type, run);
216}
217
218
219inline status_t
220Volume::Allocate(Transaction& transaction, Inode* inode, off_t numBlocks,
221	block_run& run, uint16 minimum)
222{
223	return fBlockAllocator.Allocate(transaction, inode, numBlocks, run,
224		minimum);
225}
226
227
228inline status_t
229Volume::Free(Transaction& transaction, block_run run)
230{
231	return fBlockAllocator.Free(transaction, run);
232}
233
234
235inline status_t
236Volume::FlushDevice()
237{
238	return block_cache_sync(fBlockCache);
239}
240
241
242inline Journal*
243Volume::GetJournal(off_t /*refBlock*/) const
244{
245	 return fJournal;
246}
247
248
249#endif	// VOLUME_H
250