2 * Copyright 2011, Jérôme Duval, korli@users.berlios.de.
3 * Copyright 2008-2010, Axel Dörfler, axeld@pinc-software.de.
4 * This file may be used under the terms of the MIT License.
8 //! Superblock, mounting, etc.
20 #include <fs_volume.h>
22 #include <util/AutoLock.h>
24 #include "CachedBlock.h"
27 #include "InodeJournal.h"
28 #include "NoJournal.h"
33 # define TRACE(x...) dprintf("\33[34mext2:\33[0m " x)
35 # define TRACE(x...) ;
37 # define FATAL(x...) dprintf("\33[34mext2:\33[0m " x)
42 DeviceOpener(int fd
, int mode
);
43 DeviceOpener(const char* device
, int mode
);
46 int Open(const char* device
, int mode
);
47 int Open(int fd
, int mode
);
48 void* InitCache(off_t numBlocks
, uint32 blockSize
);
49 void RemoveCache(bool allowWrites
);
53 int Device() const { return fDevice
; }
54 int Mode() const { return fMode
; }
55 bool IsReadOnly() const { return _IsReadOnly(fMode
); }
57 status_t
GetSize(off_t
* _size
, uint32
* _blockSize
= NULL
);
60 static bool _IsReadOnly(int mode
)
61 { return (mode
& O_RWMASK
) == O_RDONLY
;}
62 static bool _IsReadWrite(int mode
)
63 { return (mode
& O_RWMASK
) == O_RDWR
;}
71 DeviceOpener::DeviceOpener(const char* device
, int mode
)
79 DeviceOpener::DeviceOpener(int fd
, int mode
)
87 DeviceOpener::~DeviceOpener()
97 DeviceOpener::Open(const char* device
, int mode
)
99 fDevice
= open(device
, mode
| O_NOCACHE
);
103 if (fDevice
< 0 && _IsReadWrite(mode
)) {
104 // try again to open read-only (don't rely on a specific error code)
105 return Open(device
, O_RDONLY
| O_NOCACHE
);
111 if (_IsReadWrite(mode
)) {
112 // check out if the device really allows for read/write access
113 device_geometry geometry
;
114 if (!ioctl(fDevice
, B_GET_GEOMETRY
, &geometry
)) {
115 if (geometry
.read_only
) {
116 // reopen device read-only
118 return Open(device
, O_RDONLY
| O_NOCACHE
);
129 DeviceOpener::Open(int fd
, int mode
)
142 DeviceOpener::InitCache(off_t numBlocks
, uint32 blockSize
)
144 return fBlockCache
= block_cache_create(fDevice
, numBlocks
, blockSize
,
150 DeviceOpener::RemoveCache(bool allowWrites
)
152 if (fBlockCache
== NULL
)
155 block_cache_delete(fBlockCache
, allowWrites
);
167 /*! Returns the size of the device in bytes. It uses B_GET_GEOMETRY
168 to compute the size, or fstat() if that failed.
171 DeviceOpener::GetSize(off_t
* _size
, uint32
* _blockSize
)
173 device_geometry geometry
;
174 if (ioctl(fDevice
, B_GET_GEOMETRY
, &geometry
) < 0) {
175 // maybe it's just a file
177 if (fstat(fDevice
, &stat
) < 0)
181 *_size
= stat
.st_size
;
182 if (_blockSize
) // that shouldn't cause us any problems
189 *_size
= 1ULL * geometry
.head_count
* geometry
.cylinder_count
190 * geometry
.sectors_per_track
* geometry
.bytes_per_sector
;
193 *_blockSize
= geometry
.bytes_per_sector
;
203 ext2_super_block::IsValid()
205 if (Magic() != (uint32
)EXT2_SUPER_BLOCK_MAGIC
207 || BlocksPerGroup() != (1UL << BlockShift()) * 8
208 || InodeSize() > (1UL << BlockShift())
209 || RevisionLevel() > EXT2_MAX_REVISION
210 || ReservedGDTBlocks() > (1UL << BlockShift()) / 4) {
221 Volume::Volume(fs_volume
* volume
)
224 fBlockAllocator(NULL
),
225 fInodeAllocator(this),
231 mutex_init(&fLock
, "ext2 volume");
237 TRACE("Volume destructor.\n");
238 delete fBlockAllocator
;
239 if (fGroupBlocks
!= NULL
) {
240 uint32 blockCount
= (fNumGroups
+ fGroupsPerBlock
- 1)
242 for (uint32 i
= 0; i
< blockCount
; i
++)
243 free(fGroupBlocks
[i
]);
251 Volume::IsValidSuperBlock()
253 return fSuperBlock
.IsValid();
258 Volume::HasExtendedAttributes() const
260 return (fSuperBlock
.CompatibleFeatures() & EXT2_FEATURE_EXT_ATTR
) != 0;
267 if (fSuperBlock
.name
[0])
268 return fSuperBlock
.name
;
275 Volume::SetName(const char* name
)
277 strlcpy(fSuperBlock
.name
, name
, sizeof(fSuperBlock
.name
));
282 Volume::Mount(const char* deviceName
, uint32 flags
)
284 // flags |= B_MOUNT_READ_ONLY;
285 // we only support read-only for now
287 if ((flags
& B_MOUNT_READ_ONLY
) != 0) {
288 TRACE("Volume::Mount(): Read only\n");
290 TRACE("Volume::Mount(): Read write\n");
293 DeviceOpener
opener(deviceName
, (flags
& B_MOUNT_READ_ONLY
) != 0
294 ? O_RDONLY
: O_RDWR
);
295 fDevice
= opener
.Device();
296 if (fDevice
< B_OK
) {
297 FATAL("Volume::Mount(): couldn't open device\n");
301 if (opener
.IsReadOnly())
302 fFlags
|= VOLUME_READ_ONLY
;
304 TRACE("features %" B_PRIx32
", incompatible features %" B_PRIx32
305 ", read-only features %" B_PRIx32
"\n",
306 fSuperBlock
.CompatibleFeatures(), fSuperBlock
.IncompatibleFeatures(),
307 fSuperBlock
.ReadOnlyFeatures());
309 // read the superblock
310 status_t status
= Identify(fDevice
, &fSuperBlock
);
311 if (status
!= B_OK
) {
312 FATAL("Volume::Mount(): Identify() failed\n");
316 // check read-only features if mounting read-write
317 if (!IsReadOnly() && _UnsupportedReadOnlyFeatures(fSuperBlock
) != 0)
318 return B_UNSUPPORTED
;
320 // initialize short hands to the superblock (to save byte swapping)
321 fBlockShift
= fSuperBlock
.BlockShift();
322 if (fBlockShift
< 10 || fBlockShift
> 16)
324 fBlockSize
= 1UL << fBlockShift
;
325 fFirstDataBlock
= fSuperBlock
.FirstDataBlock();
327 fFreeBlocks
= fSuperBlock
.FreeBlocks(Has64bitFeature());
328 fFreeInodes
= fSuperBlock
.FreeInodes();
330 off_t numBlocks
= fSuperBlock
.NumBlocks(Has64bitFeature()) - fFirstDataBlock
;
331 uint32 blocksPerGroup
= fSuperBlock
.BlocksPerGroup();
332 fNumGroups
= numBlocks
/ blocksPerGroup
;
333 if (numBlocks
% blocksPerGroup
!= 0)
336 if (Has64bitFeature()) {
337 fGroupDescriptorSize
= fSuperBlock
.GroupDescriptorSize();
338 if (fGroupDescriptorSize
< sizeof(ext2_block_group
))
341 fGroupDescriptorSize
= EXT2_BLOCK_GROUP_NORMAL_SIZE
;
342 fGroupsPerBlock
= fBlockSize
/ fGroupDescriptorSize
;
343 fNumInodes
= fSuperBlock
.NumInodes();
345 TRACE("block size %" B_PRIu32
", num groups %" B_PRIu32
", groups per "
346 "block %" B_PRIu32
", first %" B_PRIu32
"\n", fBlockSize
, fNumGroups
,
347 fGroupsPerBlock
, fFirstDataBlock
);
349 uint32 blockCount
= (fNumGroups
+ fGroupsPerBlock
- 1) / fGroupsPerBlock
;
351 fGroupBlocks
= (uint8
**)malloc(blockCount
* sizeof(uint8
*));
352 if (fGroupBlocks
== NULL
)
355 memset(fGroupBlocks
, 0, blockCount
* sizeof(uint8
*));
356 fInodesPerBlock
= fBlockSize
/ InodeSize();
358 // check if the device size is large enough to hold the file system
360 status
= opener
.GetSize(&diskSize
);
363 if (diskSize
< ((off_t
)NumBlocks() << BlockShift()))
366 fBlockCache
= opener
.InitCache(NumBlocks(), fBlockSize
);
367 if (fBlockCache
== NULL
)
370 TRACE("Volume::Mount(): Initialized block cache: %p\n", fBlockCache
);
372 // initialize journal if mounted read-write
374 (fSuperBlock
.CompatibleFeatures() & EXT2_FEATURE_HAS_JOURNAL
) != 0) {
375 // TODO: There should be a mount option to ignore the existent journal
376 if (fSuperBlock
.JournalInode() != 0) {
377 fJournalInode
= new(std::nothrow
) Inode(this,
378 fSuperBlock
.JournalInode());
380 if (fJournalInode
== NULL
)
383 TRACE("Opening an on disk, inode mapped journal.\n");
384 fJournal
= new(std::nothrow
) InodeJournal(fJournalInode
);
386 // TODO: external journal
387 TRACE("Can not open an external journal.\n");
388 return B_UNSUPPORTED
;
391 TRACE("Opening a fake journal (NoJournal).\n");
392 fJournal
= new(std::nothrow
) NoJournal(this);
395 if (fJournal
== NULL
) {
396 TRACE("No memory to create the journal\n");
400 TRACE("Volume::Mount(): Checking if journal was initialized\n");
401 status
= fJournal
->InitCheck();
402 if (status
!= B_OK
) {
403 FATAL("could not initialize journal!\n");
407 // TODO: Only recover if asked to
408 TRACE("Volume::Mount(): Asking journal to recover\n");
409 status
= fJournal
->Recover();
410 if (status
!= B_OK
) {
411 FATAL("could not recover journal!\n");
415 TRACE("Volume::Mount(): Restart journal log\n");
416 status
= fJournal
->StartLog();
417 if (status
!= B_OK
) {
418 FATAL("could not initialize start journal!\n");
423 // Initialize allocators
424 fBlockAllocator
= new(std::nothrow
) BlockAllocator(this);
425 if (fBlockAllocator
!= NULL
) {
426 TRACE("Volume::Mount(): Initialize block allocator\n");
427 status
= fBlockAllocator
->Initialize();
429 if (fBlockAllocator
== NULL
|| status
!= B_OK
) {
430 delete fBlockAllocator
;
431 fBlockAllocator
= NULL
;
432 FATAL("could not initialize block allocator, going read-only!\n");
433 fFlags
|= VOLUME_READ_ONLY
;
436 delete fJournalInode
;
437 fJournalInode
= NULL
;
438 fJournal
= new(std::nothrow
) NoJournal(this);
443 status
= get_vnode(fFSVolume
, EXT2_ROOT_NODE
, (void**)&fRootNode
);
444 if (status
!= B_OK
) {
445 FATAL("could not create root node: get_vnode() failed!\n");
452 if (!fSuperBlock
.name
[0]) {
453 // generate a more or less descriptive volume name
454 off_t divisor
= 1ULL << 40;
456 if (diskSize
< divisor
) {
459 if (diskSize
< divisor
) {
465 double size
= double((10 * diskSize
+ divisor
- 1) / divisor
);
466 // %g in the kernel does not support precision...
468 snprintf(fName
, sizeof(fName
), "%g %cB Ext2 Volume",
479 TRACE("Volume::Unmount()\n");
481 status_t status
= fJournal
->Uninit();
484 delete fJournalInode
;
486 TRACE("Volume::Unmount(): Putting root node\n");
487 put_vnode(fFSVolume
, RootNode()->ID());
488 TRACE("Volume::Unmount(): Deleting the block cache\n");
489 block_cache_delete(fBlockCache
, !IsReadOnly());
490 TRACE("Volume::Unmount(): Closing device\n");
493 TRACE("Volume::Unmount(): Done\n");
499 Volume::GetInodeBlock(ino_t id
, off_t
& block
)
501 ext2_block_group
* group
;
502 status_t status
= GetBlockGroup((id
- 1) / fSuperBlock
.InodesPerGroup(),
507 block
= group
->InodeTable(Has64bitFeature())
508 + ((id
- 1) % fSuperBlock
.InodesPerGroup()) / fInodesPerBlock
;
514 Volume::InodeBlockIndex(ino_t id
) const
516 return ((id
- 1) % fSuperBlock
.InodesPerGroup()) % fInodesPerBlock
;
521 Volume::_UnsupportedIncompatibleFeatures(ext2_super_block
& superBlock
)
523 uint32 supportedIncompatible
= EXT2_INCOMPATIBLE_FEATURE_FILE_TYPE
524 | EXT2_INCOMPATIBLE_FEATURE_RECOVER
525 | EXT2_INCOMPATIBLE_FEATURE_JOURNAL
526 | EXT2_INCOMPATIBLE_FEATURE_EXTENTS
527 | EXT2_INCOMPATIBLE_FEATURE_FLEX_GROUP
;
528 /*| EXT2_INCOMPATIBLE_FEATURE_META_GROUP*/;
529 uint32 unsupported
= superBlock
.IncompatibleFeatures()
530 & ~supportedIncompatible
;
532 if (unsupported
!= 0) {
533 FATAL("ext2: incompatible features not supported: %" B_PRIx32
534 " (extents %x)\n", unsupported
, EXT2_INCOMPATIBLE_FEATURE_EXTENTS
);
542 Volume::_UnsupportedReadOnlyFeatures(ext2_super_block
& superBlock
)
544 uint32 supportedReadOnly
= EXT2_READ_ONLY_FEATURE_SPARSE_SUPER
545 | EXT2_READ_ONLY_FEATURE_LARGE_FILE
546 | EXT2_READ_ONLY_FEATURE_HUGE_FILE
547 | EXT2_READ_ONLY_FEATURE_EXTRA_ISIZE
548 | EXT2_READ_ONLY_FEATURE_DIR_NLINK
549 | EXT2_READ_ONLY_FEATURE_GDT_CSUM
;
550 // TODO actually implement EXT2_READ_ONLY_FEATURE_SPARSE_SUPER when
551 // implementing superblock backup copies
553 uint32 unsupported
= superBlock
.ReadOnlyFeatures() & ~supportedReadOnly
;
555 if (unsupported
!= 0) {
556 FATAL("ext2: readonly features not supported: %" B_PRIx32
"\n",
565 Volume::_GroupDescriptorBlock(uint32 blockIndex
)
567 if ((fSuperBlock
.IncompatibleFeatures()
568 & EXT2_INCOMPATIBLE_FEATURE_META_GROUP
) == 0
569 || blockIndex
< fSuperBlock
.FirstMetaBlockGroup())
570 return fFirstDataBlock
+ blockIndex
+ 1;
578 Volume::_GroupCheckSum(ext2_block_group
*group
, int32 index
)
581 if (HasChecksumFeature()) {
582 int32 number
= B_HOST_TO_LENDIAN_INT32(index
);
583 checksum
= calculate_crc(0xffff, fSuperBlock
.uuid
,
584 sizeof(fSuperBlock
.uuid
));
585 checksum
= calculate_crc(checksum
, (uint8
*)&number
, sizeof(number
));
586 checksum
= calculate_crc(checksum
, (uint8
*)group
, 30);
587 if (Has64bitFeature()) {
588 checksum
= calculate_crc(checksum
, (uint8
*)group
+ 34,
589 fGroupDescriptorSize
- 34);
596 /*! Makes the requested block group available.
597 The block groups are loaded on demand, but are kept in memory until the
598 volume is unmounted; therefore we don't use the block cache.
601 Volume::GetBlockGroup(int32 index
, ext2_block_group
** _group
)
603 if (index
< 0 || (uint32
)index
> fNumGroups
)
606 int32 blockIndex
= index
/ fGroupsPerBlock
;
607 int32 blockOffset
= index
% fGroupsPerBlock
;
609 MutexLocker
_(fLock
);
611 if (fGroupBlocks
[blockIndex
] == NULL
) {
612 CachedBlock
cached(this);
613 const uint8
* block
= cached
.SetTo(_GroupDescriptorBlock(blockIndex
));
617 fGroupBlocks
[blockIndex
] = (uint8
*)malloc(fBlockSize
);
618 if (fGroupBlocks
[blockIndex
] == NULL
)
621 memcpy(fGroupBlocks
[blockIndex
], block
, fBlockSize
);
623 TRACE("group [%" B_PRId32
"]: inode table %" B_PRIu64
"\n", index
,
624 ((ext2_block_group
*)(fGroupBlocks
[blockIndex
] + blockOffset
625 * fGroupDescriptorSize
))->InodeTable(Has64bitFeature()));
628 *_group
= (ext2_block_group
*)(fGroupBlocks
[blockIndex
]
629 + blockOffset
* fGroupDescriptorSize
);
630 if (HasChecksumFeature()
631 && (*_group
)->checksum
!= _GroupCheckSum(*_group
, index
)) {
639 Volume::WriteBlockGroup(Transaction
& transaction
, int32 index
)
641 if (index
< 0 || (uint32
)index
> fNumGroups
)
644 TRACE("Volume::WriteBlockGroup()\n");
646 int32 blockIndex
= index
/ fGroupsPerBlock
;
647 int32 blockOffset
= index
% fGroupsPerBlock
;
649 MutexLocker
_(fLock
);
651 if (fGroupBlocks
[blockIndex
] == NULL
)
654 ext2_block_group
*group
= (ext2_block_group
*)(fGroupBlocks
[blockIndex
]
655 + blockOffset
* fGroupDescriptorSize
);
657 group
->checksum
= _GroupCheckSum(group
, index
);
658 TRACE("Volume::WriteBlockGroup() checksum 0x%x for group %" B_PRId32
" "
659 "(free inodes %" B_PRIu32
", unused %" B_PRIu32
")\n", group
->checksum
,
660 index
, group
->FreeInodes(Has64bitFeature()),
661 group
->UnusedInodes(Has64bitFeature()));
663 CachedBlock
cached(this);
664 uint8
* block
= cached
.SetToWritable(transaction
,
665 _GroupDescriptorBlock(blockIndex
));
669 memcpy(block
, (const uint8
*)fGroupBlocks
[blockIndex
], fBlockSize
);
671 // TODO: Write copies
678 Volume::ActivateLargeFiles(Transaction
& transaction
)
680 if ((fSuperBlock
.ReadOnlyFeatures()
681 & EXT2_READ_ONLY_FEATURE_LARGE_FILE
) != 0)
684 fSuperBlock
.SetReadOnlyFeatures(fSuperBlock
.ReadOnlyFeatures()
685 | EXT2_READ_ONLY_FEATURE_LARGE_FILE
);
687 return WriteSuperBlock(transaction
);
692 Volume::ActivateDirNLink(Transaction
& transaction
)
694 if ((fSuperBlock
.ReadOnlyFeatures()
695 & EXT2_READ_ONLY_FEATURE_DIR_NLINK
) != 0)
698 fSuperBlock
.SetReadOnlyFeatures(fSuperBlock
.ReadOnlyFeatures()
699 | EXT2_READ_ONLY_FEATURE_DIR_NLINK
);
701 return WriteSuperBlock(transaction
);
706 Volume::SaveOrphan(Transaction
& transaction
, ino_t newID
, ino_t
& oldID
)
708 oldID
= fSuperBlock
.LastOrphan();
709 TRACE("Volume::SaveOrphan(): Old: %d, New: %d\n", (int)oldID
, (int)newID
);
710 fSuperBlock
.SetLastOrphan(newID
);
712 return WriteSuperBlock(transaction
);
717 Volume::RemoveOrphan(Transaction
& transaction
, ino_t id
)
719 ino_t currentID
= fSuperBlock
.LastOrphan();
720 TRACE("Volume::RemoveOrphan(): ID: %d\n", (int)id
);
724 CachedBlock
cached(this);
727 status_t status
= GetInodeBlock(currentID
, blockNum
);
731 uint8
* block
= cached
.SetToWritable(transaction
, blockNum
);
735 ext2_inode
* inode
= (ext2_inode
*)(block
736 + InodeBlockIndex(currentID
) * InodeSize());
738 if (currentID
== id
) {
739 TRACE("Volume::RemoveOrphan(): First entry. Updating head to: %d\n",
740 (int)inode
->NextOrphan());
741 fSuperBlock
.SetLastOrphan(inode
->NextOrphan());
743 return WriteSuperBlock(transaction
);
746 currentID
= inode
->NextOrphan();
751 off_t lastBlockNum
= blockNum
;
752 status
= GetInodeBlock(currentID
, blockNum
);
756 if (blockNum
!= lastBlockNum
) {
757 block
= cached
.SetToWritable(transaction
, blockNum
);
762 ext2_inode
* inode
= (ext2_inode
*)(block
763 + InodeBlockIndex(currentID
) * InodeSize());
765 currentID
= inode
->NextOrphan();
768 } while(currentID
!= id
);
770 CachedBlock
cachedRemoved(this);
772 status
= GetInodeBlock(id
, blockNum
);
776 uint8
* removedBlock
= cachedRemoved
.SetToWritable(transaction
, blockNum
);
777 if (removedBlock
== NULL
)
780 ext2_inode
* removedInode
= (ext2_inode
*)(removedBlock
781 + InodeBlockIndex(id
) * InodeSize());
783 // Next orphan is stored inside deletion time
784 inode
->deletion_time
= removedInode
->deletion_time
;
785 TRACE("Volume::RemoveOrphan(): Updated pointer to %d\n",
786 (int)inode
->NextOrphan());
793 Volume::AllocateInode(Transaction
& transaction
, Inode
* parent
, int32 mode
,
796 status_t status
= fInodeAllocator
.New(transaction
, parent
, mode
, id
);
802 return WriteSuperBlock(transaction
);
807 Volume::FreeInode(Transaction
& transaction
, ino_t id
, bool isDirectory
)
809 status_t status
= fInodeAllocator
.Free(transaction
, id
, isDirectory
);
815 return WriteSuperBlock(transaction
);
820 Volume::AllocateBlocks(Transaction
& transaction
, uint32 minimum
, uint32 maximum
,
821 uint32
& blockGroup
, fsblock_t
& start
, uint32
& length
)
823 TRACE("Volume::AllocateBlocks()\n");
825 return B_READ_ONLY_DEVICE
;
827 TRACE("Volume::AllocateBlocks(): Calling the block allocator\n");
829 status_t status
= fBlockAllocator
->AllocateBlocks(transaction
, minimum
,
830 maximum
, blockGroup
, start
, length
);
834 TRACE("Volume::AllocateBlocks(): Allocated %" B_PRIu32
" blocks\n",
837 fFreeBlocks
-= length
;
839 return WriteSuperBlock(transaction
);
844 Volume::FreeBlocks(Transaction
& transaction
, fsblock_t start
, uint32 length
)
846 TRACE("Volume::FreeBlocks(%" B_PRIu64
", %" B_PRIu32
")\n", start
, length
);
848 return B_READ_ONLY_DEVICE
;
850 status_t status
= fBlockAllocator
->Free(transaction
, start
, length
);
854 TRACE("Volume::FreeBlocks(): number of free blocks (before): %" B_PRIdOFF
856 fFreeBlocks
+= length
;
857 TRACE("Volume::FreeBlocks(): number of free blocks (after): %" B_PRIdOFF
860 return WriteSuperBlock(transaction
);
865 Volume::LoadSuperBlock()
867 CachedBlock
cached(this);
868 const uint8
* block
= cached
.SetTo(fFirstDataBlock
);
873 if (fFirstDataBlock
== 0)
874 memcpy(&fSuperBlock
, block
+ 1024, sizeof(fSuperBlock
));
876 memcpy(&fSuperBlock
, block
, sizeof(fSuperBlock
));
878 fFreeBlocks
= fSuperBlock
.FreeBlocks(Has64bitFeature());
879 fFreeInodes
= fSuperBlock
.FreeInodes();
886 Volume::WriteSuperBlock(Transaction
& transaction
)
888 TRACE("Volume::WriteSuperBlock()\n");
889 fSuperBlock
.SetFreeBlocks(fFreeBlocks
, Has64bitFeature());
890 fSuperBlock
.SetFreeInodes(fFreeInodes
);
891 // TODO: Rest of fields that can be modified
893 TRACE("Volume::WriteSuperBlock(): free blocks: %" B_PRIu64
", free inodes:"
894 " %" B_PRIu32
"\n", fSuperBlock
.FreeBlocks(Has64bitFeature()),
895 fSuperBlock
.FreeInodes());
897 CachedBlock
cached(this);
898 uint8
* block
= cached
.SetToWritable(transaction
, fFirstDataBlock
);
903 TRACE("Volume::WriteSuperBlock(): first data block: %" B_PRIu32
", block:"
904 " %p, superblock: %p\n", fFirstDataBlock
, block
, &fSuperBlock
);
906 if (fFirstDataBlock
== 0)
907 memcpy(block
+ 1024, &fSuperBlock
, sizeof(fSuperBlock
));
909 memcpy(block
, &fSuperBlock
, sizeof(fSuperBlock
));
911 TRACE("Volume::WriteSuperBlock(): Done\n");
918 Volume::FlushDevice()
920 TRACE("Volume::FlushDevice(): %p, %p\n", this, fBlockCache
);
921 return block_cache_sync(fBlockCache
);
928 TRACE("Volume::Sync()\n");
929 return fJournal
->Uninit();
933 // #pragma mark - Disk scanning and initialization
937 Volume::Identify(int fd
, ext2_super_block
* superBlock
)
939 if (read_pos(fd
, EXT2_SUPER_BLOCK_OFFSET
, superBlock
,
940 sizeof(ext2_super_block
)) != sizeof(ext2_super_block
))
943 if (!superBlock
->IsValid()) {
944 FATAL("invalid superblock!\n");
948 return _UnsupportedIncompatibleFeatures(*superBlock
) == 0
949 ? B_OK
: B_UNSUPPORTED
;
954 Volume::TransactionDone(bool success
)
957 status_t status
= LoadSuperBlock();
959 panic("Failed to reload ext2 superblock.\n");
965 Volume::RemovedFromTransaction()
967 // TODO: Does it make a difference?