xref: /haiku/src/add-ons/kernel/file_systems/btrfs/Volume.cpp (revision 9e15c9f153c5ffff9ad51b95b581326eb579b0fd)
1 /*
2  * Copyright 2019, Les De Ridder, les@lesderid.net
3  * Copyright 2017, Chế Vũ Gia Hy, cvghy116@gmail.com.
4  * Copyright 2011, Jérôme Duval, korli@users.berlios.de.
5  * Copyright 2008-2010, Axel Dörfler, axeld@pinc-software.de.
6  *
7  * This file may be used under the terms of the MIT License.
8  */
9 
10 
11 //! Superblock, mounting, etc.
12 
13 
14 #include "Volume.h"
15 #include "BTree.h"
16 #include "CachedBlock.h"
17 #include "Chunk.h"
18 #include "CRCTable.h"
19 #include "DebugSupport.h"
20 #include "ExtentAllocator.h"
21 #include "Inode.h"
22 #include "Journal.h"
23 #include "Utility.h"
24 
25 
26 //#define TRACE_BTRFS
27 #ifdef TRACE_BTRFS
28 #	define TRACE(x...) dprintf("\33[34mbtrfs:\33[0m " x)
29 #else
30 #	define TRACE(x...) ;
31 #endif
32 
33 
34 class DeviceOpener {
35 public:
36 								DeviceOpener(int fd, int mode);
37 								DeviceOpener(const char* device, int mode);
38 								~DeviceOpener();
39 
40 			int					Open(const char* device, int mode);
41 			int					Open(int fd, int mode);
42 			void*				InitCache(off_t numBlocks, uint32 blockSize);
43 			void				RemoveCache(bool allowWrites);
44 
45 			void				Keep();
46 
47 			int					Device() const { return fDevice; }
48 			int					Mode() const { return fMode; }
49 			bool				IsReadOnly() const
50 									{ return _IsReadOnly(fMode); }
51 
52 			status_t			GetSize(off_t* _size, uint32* _blockSize = NULL);
53 
54 private:
55 	static	bool				_IsReadOnly(int mode)
56 									{ return (mode & O_RWMASK) == O_RDONLY;}
57 	static	bool				_IsReadWrite(int mode)
58 									{ return (mode & O_RWMASK) == O_RDWR;}
59 
60 			int					fDevice;
61 			int					fMode;
62 			void*				fBlockCache;
63 };
64 
65 
66 DeviceOpener::DeviceOpener(const char* device, int mode)
67 	:
68 	fBlockCache(NULL)
69 {
70 	Open(device, mode);
71 }
72 
73 
74 DeviceOpener::DeviceOpener(int fd, int mode)
75 	:
76 	fBlockCache(NULL)
77 {
78 	Open(fd, mode);
79 }
80 
81 
82 DeviceOpener::~DeviceOpener()
83 {
84 	if (fDevice >= 0) {
85 		RemoveCache(false);
86 		close(fDevice);
87 	}
88 }
89 
90 
91 int
92 DeviceOpener::Open(const char* device, int mode)
93 {
94 	fDevice = open(device, mode | O_NOCACHE);
95 	if (fDevice < 0)
96 		fDevice = errno;
97 
98 	if (fDevice < 0 && _IsReadWrite(mode)) {
99 		// try again to open read-only (don't rely on a specific error code)
100 		return Open(device, O_RDONLY | O_NOCACHE);
101 	}
102 
103 	if (fDevice >= 0) {
104 		// opening succeeded
105 		fMode = mode;
106 		if (_IsReadWrite(mode)) {
107 			// check out if the device really allows for read/write access
108 			device_geometry geometry;
109 			if (!ioctl(fDevice, B_GET_GEOMETRY, &geometry, sizeof(device_geometry))) {
110 				if (geometry.read_only) {
111 					// reopen device read-only
112 					close(fDevice);
113 					return Open(device, O_RDONLY | O_NOCACHE);
114 				}
115 			}
116 		}
117 	}
118 
119 	return fDevice;
120 }
121 
122 
123 int
124 DeviceOpener::Open(int fd, int mode)
125 {
126 	fDevice = dup(fd);
127 	if (fDevice < 0)
128 		return errno;
129 
130 	fMode = mode;
131 
132 	return fDevice;
133 }
134 
135 
136 void*
137 DeviceOpener::InitCache(off_t numBlocks, uint32 blockSize)
138 {
139 	return fBlockCache = block_cache_create(fDevice, numBlocks, blockSize,
140 		IsReadOnly());
141 }
142 
143 
144 void
145 DeviceOpener::RemoveCache(bool allowWrites)
146 {
147 	if (fBlockCache == NULL)
148 		return;
149 
150 	block_cache_delete(fBlockCache, allowWrites);
151 	fBlockCache = NULL;
152 }
153 
154 
155 void
156 DeviceOpener::Keep()
157 {
158 	fDevice = -1;
159 }
160 
161 
162 /*!	Returns the size of the device in bytes. It uses B_GET_GEOMETRY
163 	to compute the size, or fstat() if that failed.
164 */
165 status_t
166 DeviceOpener::GetSize(off_t* _size, uint32* _blockSize)
167 {
168 	device_geometry geometry;
169 	if (ioctl(fDevice, B_GET_GEOMETRY, &geometry, sizeof(device_geometry)) < 0) {
170 		// maybe it's just a file
171 		struct stat stat;
172 		if (fstat(fDevice, &stat) < 0)
173 			return B_ERROR;
174 
175 		if (_size)
176 			*_size = stat.st_size;
177 		if (_blockSize)	// that shouldn't cause us any problems
178 			*_blockSize = 512;
179 
180 		return B_OK;
181 	}
182 
183 	if (_size) {
184 		*_size = 1ULL * geometry.head_count * geometry.cylinder_count
185 			* geometry.sectors_per_track * geometry.bytes_per_sector;
186 	}
187 	if (_blockSize)
188 		*_blockSize = geometry.bytes_per_sector;
189 
190 	return B_OK;
191 }
192 
193 
194 //	#pragma mark -
195 
196 
197 bool
198 btrfs_super_block::IsValid() const
199 {
200 	// TODO: check some more values!
201 	if (strncmp(magic, BTRFS_SUPER_BLOCK_MAGIC, sizeof(magic)) != 0)
202 		return false;
203 
204 	return true;
205 }
206 
207 
208 void
209 btrfs_super_block::Initialize(const char* name, off_t numBlocks,
210 		uint32 blockSize, uint32 sectorSize)
211 {
212 	memset(this, 0, sizeof(btrfs_super_block));
213 
214 	uuid_generate(fsid);
215 	blocknum = B_HOST_TO_LENDIAN_INT64(BTRFS_SUPER_BLOCK_OFFSET);
216 	num_devices = B_HOST_TO_LENDIAN_INT64(1);
217 	strncpy(magic, BTRFS_SUPER_BLOCK_MAGIC_TEMPORARY, sizeof(magic));
218 	generation = B_HOST_TO_LENDIAN_INT64(1);
219 	root = B_HOST_TO_LENDIAN_INT64(BTRFS_RESERVED_SPACE_OFFSET + blockSize);
220 	chunk_root = B_HOST_TO_LENDIAN_INT64(Root() + blockSize);
221 	total_size = B_HOST_TO_LENDIAN_INT64(numBlocks * blockSize);
222 	used_size = B_HOST_TO_LENDIAN_INT64(6 * blockSize);
223 	sector_size = B_HOST_TO_LENDIAN_INT32(sectorSize);
224 	leaf_size = B_HOST_TO_LENDIAN_INT32(blockSize);
225 	node_size = B_HOST_TO_LENDIAN_INT32(blockSize);
226 	stripe_size = B_HOST_TO_LENDIAN_INT32(blockSize);
227 	checksum_type = B_HOST_TO_LENDIAN_INT32(BTRFS_CSUM_TYPE_CRC32);
228 	chunk_root_generation = B_HOST_TO_LENDIAN_INT64(1);
229 	// TODO(lesderid): Support configurable filesystem features
230 	incompat_flags = B_HOST_TO_LENDIAN_INT64(0);
231 	strlcpy(label, name, BTRFS_LABEL_SIZE);
232 }
233 
234 
235 //	#pragma mark -
236 
237 
238 Volume::Volume(fs_volume* volume)
239 	:
240 	fFSVolume(volume),
241 	fFlags(0),
242 	fChunk(NULL),
243 	fChunkTree(NULL)
244 {
245 	mutex_init(&fLock, "btrfs volume");
246 }
247 
248 
249 Volume::~Volume()
250 {
251 	TRACE("Volume destructor.\n");
252 }
253 
254 
255 bool
256 Volume::IsValidSuperBlock()
257 {
258 	return fSuperBlock.IsValid();
259 }
260 
261 
262 const char*
263 Volume::Name() const
264 {
265 	if (fSuperBlock.label[0])
266 		return fSuperBlock.label;
267 
268 	return fName;
269 }
270 
271 
272 status_t
273 Volume::Mount(const char* deviceName, uint32 flags)
274 {
275 	flags |= B_MOUNT_READ_ONLY;
276 		// we only support read-only for now
277 
278 	if ((flags & B_MOUNT_READ_ONLY) != 0) {
279 		TRACE("Volume::Mount(): Read only\n");
280 	} else {
281 		TRACE("Volume::Mount(): Read write\n");
282 	}
283 
284 	DeviceOpener opener(deviceName, (flags & B_MOUNT_READ_ONLY) != 0
285 		? O_RDONLY : O_RDWR);
286 	fDevice = opener.Device();
287 	if (fDevice < B_OK) {
288 		ERROR("Volume::Mount(): couldn't open device\n");
289 		return fDevice;
290 	}
291 
292 	if (opener.IsReadOnly())
293 		fFlags |= VOLUME_READ_ONLY;
294 
295 	// read the superblock
296 	status_t status = Identify(fDevice, &fSuperBlock);
297 	if (status != B_OK) {
298 		ERROR("Volume::Mount(): Identify() failed\n");
299 		return status;
300 	}
301 
302 	fBlockSize = fSuperBlock.BlockSize();
303 	fSectorSize = fSuperBlock.SectorSize();
304 	TRACE("block size %" B_PRIu32 "\n", fBlockSize);
305 	TRACE("sector size %" B_PRIu32 "\n", fSectorSize);
306 
307 	uint8* start = (uint8*)&fSuperBlock.system_chunk_array[0];
308 	uint8* end = (uint8*)&fSuperBlock.system_chunk_array[2048];
309 	while (start < end) {
310 		btrfs_key* key = (btrfs_key*)start;
311 		TRACE("system_chunk_array object_id 0x%" B_PRIx64 " offset 0x%"
312 			B_PRIx64 " type 0x%x\n", key->ObjectID(), key->Offset(),
313 			key->Type());
314 		if (key->Type() != BTRFS_KEY_TYPE_CHUNK_ITEM) {
315 			break;
316 		}
317 
318 		btrfs_chunk* chunk = (btrfs_chunk*)(key + 1);
319 		fChunk = new(std::nothrow) Chunk(chunk, key->Offset());
320 		if (fChunk == NULL)
321 			return B_ERROR;
322 		start += sizeof(btrfs_key) + fChunk->Size();
323 	}
324 
325 	// check if the device size is large enough to hold the file system
326 	off_t diskSize;
327 	status = opener.GetSize(&diskSize);
328 	if (status != B_OK)
329 		return status;
330 	if (diskSize < (off_t)fSuperBlock.TotalSize())
331 		return B_BAD_VALUE;
332 
333 	fBlockCache = opener.InitCache(fSuperBlock.TotalSize() / fBlockSize,
334 		fBlockSize);
335 	if (fBlockCache == NULL)
336 		return B_ERROR;
337 
338 	TRACE("Volume::Mount(): Initialized block cache: %p\n", fBlockCache);
339 
340 	fChunkTree = new(std::nothrow) BTree(this);
341 	if (fChunkTree == NULL)
342 		return B_NO_MEMORY;
343 	fChunkTree->SetRoot(fSuperBlock.ChunkRoot(), NULL);
344 	TRACE("Volume::Mount() chunk_root: %" B_PRIu64 " (physical block %" B_PRIu64
345 		")\n", fSuperBlock.ChunkRoot(), fChunkTree->RootBlock());
346 
347 	fRootTree = new(std::nothrow) BTree(this);
348 	if (fRootTree == NULL)
349 		return B_NO_MEMORY;
350 	fRootTree->SetRoot(fSuperBlock.Root(), NULL);
351 	TRACE("Volume::Mount() root: %" B_PRIu64 " (physical block %" B_PRIu64 ")\n",
352 		fSuperBlock.Root(), fRootTree->RootBlock());
353 
354 	BTree::Path path(fRootTree);
355 
356 	TRACE("Volume::Mount(): Searching extent root\n");
357 	btrfs_key search_key;
358 	search_key.SetOffset(0);
359 	search_key.SetType(BTRFS_KEY_TYPE_ROOT_ITEM);
360 	search_key.SetObjectID(BTRFS_OBJECT_ID_EXTENT_TREE);
361 	btrfs_root* root;
362 	status = fRootTree->FindExact(&path, search_key, (void**)&root);
363 	if (status != B_OK) {
364 		ERROR("Volume::Mount(): Couldn't find extent root\n");
365 		return status;
366 	}
367 	TRACE("Volume::Mount(): Found extent root: %" B_PRIu64 "\n",
368 		root->LogicalAddress());
369 	fExtentTree = new(std::nothrow) BTree(this);
370 	if (fExtentTree == NULL)
371 		return B_NO_MEMORY;
372 	fExtentTree->SetRoot(root->LogicalAddress(), NULL);
373 	free(root);
374 
375 	TRACE("Volume::Mount(): Searching fs root\n");
376 	search_key.SetOffset(0);
377 	search_key.SetObjectID(BTRFS_OBJECT_ID_FS_TREE);
378 	status = fRootTree->FindExact(&path, search_key, (void**)&root);
379 	if (status != B_OK) {
380 		ERROR("Volume::Mount(): Couldn't find fs root\n");
381 		return status;
382 	}
383 	TRACE("Volume::Mount(): Found fs root: %" B_PRIu64 "\n",
384 		root->LogicalAddress());
385 	fFSTree = new(std::nothrow) BTree(this);
386 	if (fFSTree == NULL)
387 		return B_NO_MEMORY;
388 	fFSTree->SetRoot(root->LogicalAddress(), NULL);
389 	free(root);
390 
391 	TRACE("Volume::Mount(): Searching dev root\n");
392 	search_key.SetOffset(0);
393 	search_key.SetObjectID(BTRFS_OBJECT_ID_DEV_TREE);
394 	status = fRootTree->FindExact(&path, search_key, (void**)&root);
395 	if (status != B_OK) {
396 		ERROR("Volume::Mount(): Couldn't find dev root\n");
397 		return status;
398 	}
399 	TRACE("Volume::Mount(): Found dev root: %" B_PRIu64 "\n",
400 		root->LogicalAddress());
401 	fDevTree = new(std::nothrow) BTree(this);
402 	if (fDevTree == NULL)
403 		return B_NO_MEMORY;
404 	fDevTree->SetRoot(root->LogicalAddress(), NULL);
405 	free(root);
406 
407 	TRACE("Volume::Mount(): Searching checksum root\n");
408 	search_key.SetOffset(0);
409 	search_key.SetObjectID(BTRFS_OBJECT_ID_CHECKSUM_TREE);
410 	status = fRootTree->FindExact(&path, search_key, (void**)&root);
411 	if (status != B_OK) {
412 		ERROR("Volume::Mount(): Couldn't find checksum root\n");
413 		return status;
414 	}
415 	TRACE("Volume::Mount(): Found checksum root: %" B_PRIu64 "\n",
416 		root->LogicalAddress());
417 	fChecksumTree = new(std::nothrow) BTree(this);
418 	if (fChecksumTree == NULL)
419 		return B_NO_MEMORY;
420 	fChecksumTree->SetRoot(root->LogicalAddress(), NULL);
421 	free(root);
422 
423 	search_key.SetObjectID(-1);
424 	search_key.SetType(0);
425 	status = fFSTree->FindPrevious(&path, search_key, NULL);
426 	if (status != B_OK) {
427 		ERROR("Volume::Mount() Couldn't find any inode!!\n");
428 		return status;
429 	}
430 	fLargestInodeID = search_key.ObjectID();
431 	TRACE("Volume::Mount() Find larget inode id % " B_PRIu64 "\n",
432 		fLargestInodeID);
433 
434 	if ((flags & B_MOUNT_READ_ONLY) != 0) {
435 		fJournal = NULL;
436 		fExtentAllocator = NULL;
437 	} else {
438 		// Initialize Journal
439 		fJournal = new(std::nothrow) Journal(this);
440 		if (fJournal == NULL)
441 			return B_NO_MEMORY;
442 
443 		// Initialize ExtentAllocator;
444 		fExtentAllocator = new(std::nothrow) ExtentAllocator(this);
445 		if (fExtentAllocator == NULL)
446 			return B_NO_MEMORY;
447 		status = fExtentAllocator->Initialize();
448 		if (status != B_OK) {
449 			ERROR("could not initalize extent allocator!\n");
450 			return status;
451 		}
452 	}
453 
454 	// ready
455 	status = get_vnode(fFSVolume, BTRFS_FIRST_SUBVOLUME,
456 		(void**)&fRootNode);
457 	if (status != B_OK) {
458 		ERROR("could not create root node: get_vnode() failed!\n");
459 		return status;
460 	}
461 
462 	TRACE("Volume::Mount(): Found root node: %" B_PRIu64 " (%s)\n",
463 		fRootNode->ID(), strerror(fRootNode->InitCheck()));
464 
465 	// all went fine
466 	opener.Keep();
467 
468 	if (!fSuperBlock.label[0]) {
469 		// generate a more or less descriptive volume name
470 		off_t divisor = 1ULL << 40;
471 		char unit = 'T';
472 		if (diskSize < divisor) {
473 			divisor = 1UL << 30;
474 			unit = 'G';
475 			if (diskSize < divisor) {
476 				divisor = 1UL << 20;
477 				unit = 'M';
478 			}
479 		}
480 
481 		double size = double((10 * diskSize + divisor - 1) / divisor);
482 			// %g in the kernel does not support precision...
483 
484 		snprintf(fName, sizeof(fName), "%g %cB Btrfs Volume",
485 			size / 10, unit);
486 	}
487 
488 	return B_OK;
489 }
490 
491 
492 status_t
493 Volume::Initialize(int fd, const char* label, uint32 blockSize,
494 	uint32 sectorSize)
495 {
496 	TRACE("Volume::Initialize()\n");
497 
498 	// label must != NULL and may not contain '/' or '\\'
499 	if (label == NULL
500 		|| strchr(label, '/') != NULL || strchr(label, '\\') != NULL) {
501 		return B_BAD_VALUE;
502 	}
503 
504 	if ((blockSize != 1024 && blockSize != 2048 && blockSize != 4096
505 		&& blockSize != 8192 && blockSize != 16384)
506 		|| blockSize % sectorSize != 0) {
507 		return B_BAD_VALUE;
508 	}
509 
510 	DeviceOpener opener(fd, O_RDWR);
511 	if (opener.Device() < B_OK)
512 		return B_BAD_VALUE;
513 
514 	if (opener.IsReadOnly())
515 		return B_READ_ONLY_DEVICE;
516 
517 	fDevice = opener.Device();
518 
519 	uint32 deviceBlockSize;
520 	off_t deviceSize;
521 	if (opener.GetSize(&deviceSize, &deviceBlockSize) < B_OK)
522 		return B_ERROR;
523 	off_t numBlocks = deviceSize / sectorSize;
524 
525 	// create valid superblock
526 
527 	fSuperBlock.Initialize(label, numBlocks, blockSize, sectorSize);
528 
529 	fBlockSize = fSuperBlock.BlockSize();
530 	fSectorSize = fSuperBlock.SectorSize();
531 
532 	// TODO(lesderid):	Initialize remaining core structures
533 	//					(extent tree, chunk tree, fs tree, etc.)
534 
535 	status_t status = WriteSuperBlock();
536 	if (status < B_OK)
537 		return status;
538 
539 	fBlockCache = opener.InitCache(fSuperBlock.TotalSize() / fBlockSize,
540 		fBlockSize);
541 	if (fBlockCache == NULL)
542 		return B_ERROR;
543 
544 	fJournal = new(std::nothrow) Journal(this);
545 	if (fJournal == NULL)
546 		RETURN_ERROR(B_ERROR);
547 
548 	// TODO(lesderid):	Perform secondary initialization (in transactions)
549 	//					(add block groups to extent tree, create root dir, etc.)
550 	Transaction transaction(this);
551 
552 	// TODO(lesderid): Write all superblocks when transactions are committed
553 	status = transaction.Done();
554 	if (status < B_OK)
555 		return status;
556 
557 	opener.RemoveCache(true);
558 
559 	TRACE("Volume::Initialize(): Done\n");
560 	return B_OK;
561 }
562 
563 
564 status_t
565 Volume::Unmount()
566 {
567 	TRACE("Volume::Unmount()\n");
568 	delete fRootTree;
569 	delete fExtentTree;
570 	delete fChunkTree;
571 	delete fChecksumTree;
572 	delete fFSTree;
573 	delete fDevTree;
574 	delete fJournal;
575 	delete fExtentAllocator;
576 	fRootTree = NULL;
577 	fExtentTree = NULL;
578 	fChunkTree = NULL;
579 	fChecksumTree = NULL;
580 	fFSTree = NULL;
581 	fDevTree = NULL;
582 	fJournal = NULL;
583 	fExtentAllocator = NULL;
584 
585 	TRACE("Volume::Unmount(): Putting root node\n");
586 	put_vnode(fFSVolume, RootNode()->ID());
587 	TRACE("Volume::Unmount(): Deleting the block cache\n");
588 	block_cache_delete(fBlockCache, !IsReadOnly());
589 	TRACE("Volume::Unmount(): Closing device\n");
590 	close(fDevice);
591 
592 	TRACE("Volume::Unmount(): Done\n");
593 	return B_OK;
594 }
595 
596 
597 status_t
598 Volume::LoadSuperBlock()
599 {
600 	CachedBlock cached(this);
601 	const uint8* block = cached.SetTo(BTRFS_SUPER_BLOCK_OFFSET / fBlockSize);
602 
603 	if (block == NULL)
604 		return B_IO_ERROR;
605 
606 	memcpy(&fSuperBlock, block + BTRFS_SUPER_BLOCK_OFFSET % fBlockSize,
607 		sizeof(fSuperBlock));
608 
609 	return B_OK;
610 }
611 
612 
613 status_t
614 Volume::FindBlock(off_t logical, fsblock_t& physicalBlock)
615 {
616 	off_t physical;
617 	status_t status = FindBlock(logical, physical);
618 	if (status != B_OK)
619 		return status;
620 	physicalBlock = physical / fBlockSize;
621 	return B_OK;
622 }
623 
624 
625 status_t
626 Volume::FindBlock(off_t logical, off_t& physical)
627 {
628 	if (fChunkTree == NULL
629 		|| (logical >= (off_t)fChunk->Offset()
630 			&& logical < (off_t)fChunk->End())) {
631 		// try with fChunk
632 		return fChunk->FindBlock(logical, physical);
633 	}
634 
635 	btrfs_key search_key;
636 	search_key.SetOffset(logical);
637 	search_key.SetType(BTRFS_KEY_TYPE_CHUNK_ITEM);
638 	search_key.SetObjectID(BTRFS_OBJECT_ID_FIRST_CHUNK_TREE);
639 	btrfs_chunk* chunk;
640 	BTree::Path path(fChunkTree);
641 	status_t status = fChunkTree->FindPrevious(&path, search_key,
642 		(void**)&chunk);
643 	if (status != B_OK)
644 		return status;
645 
646 	Chunk _chunk(chunk, search_key.Offset());
647 	free(chunk);
648 	status = _chunk.FindBlock(logical, physical);
649 	if (status != B_OK)
650 			return status;
651 	TRACE("Volume::FindBlock(): logical: %" B_PRIdOFF ", physical: %" B_PRIdOFF
652 		"\n", logical, physical);
653 	return B_OK;
654 }
655 
656 
657 status_t
658 Volume::WriteSuperBlock()
659 {
660 	uint32 checksum = calculate_crc((uint32)~1,
661 			(uint8 *)(&fSuperBlock + sizeof(fSuperBlock.checksum)),
662 			sizeof(fSuperBlock) - sizeof(fSuperBlock.checksum));
663 
664 	fSuperBlock.checksum[0] = (checksum >>  0) & 0xFF;
665 	fSuperBlock.checksum[1] = (checksum >>  8) & 0xFF;
666 	fSuperBlock.checksum[2] = (checksum >> 16) & 0xFF;
667 	fSuperBlock.checksum[3] = (checksum >> 24) & 0xFF;
668 
669 	if (write_pos(fDevice, BTRFS_SUPER_BLOCK_OFFSET, &fSuperBlock,
670 			sizeof(btrfs_super_block))
671 		!= sizeof(btrfs_super_block))
672 		return B_IO_ERROR;
673 
674 	return B_OK;
675 }
676 
677 
678 /* Wrapper function for allocating new block
679  */
680 status_t
681 Volume::GetNewBlock(uint64& logical, fsblock_t& physical, uint64 start,
682 	uint64 flags)
683 {
684 	status_t status = fExtentAllocator->AllocateTreeBlock(logical, start, flags);
685 	if (status != B_OK)
686 		return status;
687 
688 	return FindBlock(logical, physical);
689 }
690 
691 
692 //	#pragma mark - Disk scanning and initialization
693 
694 
695 /*static*/ status_t
696 Volume::Identify(int fd, btrfs_super_block* superBlock)
697 {
698 	if (read_pos(fd, BTRFS_SUPER_BLOCK_OFFSET, superBlock,
699 			sizeof(btrfs_super_block)) != sizeof(btrfs_super_block))
700 		return B_IO_ERROR;
701 
702 	if (!superBlock->IsValid()) {
703 		ERROR("invalid superblock!\n");
704 		return B_BAD_VALUE;
705 	}
706 
707 	return B_OK;
708 }
709 
710