diff --git a/src/add-ons/kernel/file_systems/bfs/Debug.cpp b/src/add-ons/kernel/file_systems/bfs/Debug.cpp index 1ba8dc3e09..89793e8ff5 100644 --- a/src/add-ons/kernel/file_systems/bfs/Debug.cpp +++ b/src/add-ons/kernel/file_systems/bfs/Debug.cpp @@ -117,12 +117,15 @@ dump_inode(const bfs_inode* inode) kprintf(" gid = %u\n", (unsigned)inode->GroupID()); kprintf(" mode = %08x\n", (int)inode->Mode()); kprintf(" flags = %08x\n", (int)inode->Flags()); - kprintf(" create_time = %Ld (%Ld)\n", inode->CreateTime(), - inode->CreateTime() >> INODE_TIME_SHIFT); - kprintf(" last_modified_time = %Ld (%Ld)\n", inode->LastModifiedTime(), - inode->LastModifiedTime() >> INODE_TIME_SHIFT); - kprintf(" status_change_time = %Ld (%Ld)\n", inode->StatusChangeTime(), - inode->StatusChangeTime() >> INODE_TIME_SHIFT); + kprintf(" create_time = %llx (%ld.%u)\n", inode->CreateTime(), + bfs_inode::ToSecs(inode->CreateTime()), + (unsigned)bfs_inode::ToUsecs(inode->CreateTime())); + kprintf(" last_modified_time = %llx (%ld.%u)\n", inode->LastModifiedTime(), + bfs_inode::ToSecs(inode->LastModifiedTime()), + (unsigned)bfs_inode::ToUsecs(inode->LastModifiedTime())); + kprintf(" status_change_time = %llx (%ld.%u)\n", inode->StatusChangeTime(), + bfs_inode::ToSecs(inode->StatusChangeTime()), + (unsigned)bfs_inode::ToUsecs(inode->StatusChangeTime())); dump_block_run( " parent = ", inode->parent); dump_block_run( " attributes = ", inode->attributes); kprintf(" type = %u\n", (unsigned)inode->Type()); diff --git a/src/add-ons/kernel/file_systems/bfs/Index.cpp b/src/add-ons/kernel/file_systems/bfs/Index.cpp index f76c52fbaa..f3a569d7bd 100644 --- a/src/add-ons/kernel/file_systems/bfs/Index.cpp +++ b/src/add-ons/kernel/file_systems/bfs/Index.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2001-2008, Axel Dörfler, axeld@pinc-software.de. + * Copyright 2001-2009, Axel Dörfler, axeld@pinc-software.de. * This file may be used under the terms of the MIT License. */ @@ -390,9 +390,7 @@ Index::UpdateLastModified(Transaction &transaction, Inode* inode, bigtime_t oldModified = inode->OldLastModified(); if (modified == -1) - modified = (bigtime_t)time(NULL) << INODE_TIME_SHIFT; - modified &= ~INODE_TIME_MASK; - modified |= fVolume->GetUniqueID() & INODE_TIME_MASK; + modified = bfs_inode::ToInode(real_time_clock_usecs()); status_t status = Update(transaction, "last_modified", B_INT64_TYPE, (uint8*)&oldModified, sizeof(int64), (uint8*)&modified, diff --git a/src/add-ons/kernel/file_systems/bfs/Inode.cpp b/src/add-ons/kernel/file_systems/bfs/Inode.cpp index e53d65580b..e96063af32 100644 --- a/src/add-ons/kernel/file_systems/bfs/Inode.cpp +++ b/src/add-ons/kernel/file_systems/bfs/Inode.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2001-2008, Axel Dörfler, axeld@pinc-software.de. + * Copyright 2001-2009, Axel Dörfler, axeld@pinc-software.de. * This file may be used under the terms of the MIT License. */ @@ -389,13 +389,8 @@ Inode::Inode(Volume* volume, Transaction& transaction, ino_t id, mode_t mode, Node().mode = HOST_ENDIAN_TO_BFS_INT32(mode); Node().flags = HOST_ENDIAN_TO_BFS_INT32(INODE_IN_USE); - Node().create_time = HOST_ENDIAN_TO_BFS_INT64((bigtime_t)time(NULL) - << INODE_TIME_SHIFT); - Node().last_modified_time = HOST_ENDIAN_TO_BFS_INT64(Node().create_time - | (volume->GetUniqueID() & INODE_TIME_MASK)); - // we use Volume::GetUniqueID() to avoid having too many duplicates - // in the last_modified index - Node().status_change_time = HOST_ENDIAN_TO_BFS_INT64(Node().create_time); + Node().create_time = Node().last_modified_time = Node().status_change_time + = HOST_ENDIAN_TO_BFS_INT64(bfs_inode::ToInode(real_time_clock_usecs())); Node().inode_size = HOST_ENDIAN_TO_BFS_INT32(volume->InodeSize()); @@ -1468,8 +1463,8 @@ Inode::WriteAt(Transaction& transaction, off_t pos, const uint8* buffer, // update the last modification time in memory, it will be written // back to the inode, and the index when the file is closed // TODO: should update the internal last modified time only at this point! - Node().last_modified_time = HOST_ENDIAN_TO_BFS_INT64((bigtime_t)time(NULL) - << INODE_TIME_SHIFT); + Node().last_modified_time + = HOST_ENDIAN_TO_BFS_INT64(bfs_inode::ToInode(real_time_clock_usecs())); // TODO: support INODE_LOGGED! diff --git a/src/add-ons/kernel/file_systems/bfs/Volume.cpp b/src/add-ons/kernel/file_systems/bfs/Volume.cpp index 02839b5a9a..53722210ca 100644 --- a/src/add-ons/kernel/file_systems/bfs/Volume.cpp +++ b/src/add-ons/kernel/file_systems/bfs/Volume.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2001-2008, Axel Dörfler, axeld@pinc-software.de. + * Copyright 2001-2009, Axel Dörfler, axeld@pinc-software.de. * This file may be used under the terms of the MIT License. */ @@ -279,7 +279,6 @@ Volume::Volume(fs_volume* volume) fRootNode(NULL), fIndicesNode(NULL), fDirtyCachedBlocks(0), - fUniqueID(0), fFlags(0), fCheckingThread(-1) { diff --git a/src/add-ons/kernel/file_systems/bfs/Volume.h b/src/add-ons/kernel/file_systems/bfs/Volume.h index 1192ecc6db..37e1a5a928 100644 --- a/src/add-ons/kernel/file_systems/bfs/Volume.h +++ b/src/add-ons/kernel/file_systems/bfs/Volume.h @@ -126,8 +126,6 @@ public: void* BlockCache() { return fBlockCache; } - uint32 GetUniqueID(); - static status_t CheckSuperBlock(const uint8* data, uint32* _offset = NULL); static status_t Identify(int fd, disk_super_block* superBlock); @@ -155,7 +153,6 @@ protected: mutex fQueryLock; SinglyLinkedList fQueries; - int32 fUniqueID; uint32 fFlags; void* fBlockCache; @@ -226,10 +223,4 @@ Volume::GetJournal(off_t /*refBlock*/) const } -inline uint32 -Volume::GetUniqueID() -{ - return atomic_add(&fUniqueID, 1); -} - #endif // VOLUME_H diff --git a/src/add-ons/kernel/file_systems/bfs/bfs.h b/src/add-ons/kernel/file_systems/bfs/bfs.h index f46496f07d..54991e1de3 100644 --- a/src/add-ons/kernel/file_systems/bfs/bfs.h +++ b/src/add-ons/kernel/file_systems/bfs/bfs.h @@ -28,7 +28,8 @@ struct block_run { uint16 start; uint16 length; - int32 AllocationGroup() const { return BFS_ENDIAN_TO_HOST_INT32(allocation_group); } + int32 AllocationGroup() const + { return BFS_ENDIAN_TO_HOST_INT32(allocation_group); } uint16 Start() const { return BFS_ENDIAN_TO_HOST_INT16(start); } uint16 Length() const { return BFS_ENDIAN_TO_HOST_INT16(length); } @@ -87,9 +88,11 @@ struct disk_super_block { off_t NumBlocks() const { return BFS_ENDIAN_TO_HOST_INT64(num_blocks); } off_t UsedBlocks() const { return BFS_ENDIAN_TO_HOST_INT64(used_blocks); } int32 InodeSize() const { return BFS_ENDIAN_TO_HOST_INT32(inode_size); } - int32 BlocksPerAllocationGroup() const { return BFS_ENDIAN_TO_HOST_INT32(blocks_per_ag); } + int32 BlocksPerAllocationGroup() const + { return BFS_ENDIAN_TO_HOST_INT32(blocks_per_ag); } int32 AllocationGroups() const { return BFS_ENDIAN_TO_HOST_INT32(num_ags); } - int32 AllocationGroupShift() const { return BFS_ENDIAN_TO_HOST_INT32(ag_shift); } + int32 AllocationGroupShift() const + { return BFS_ENDIAN_TO_HOST_INT32(ag_shift); } int32 Flags() const { return BFS_ENDIAN_TO_HOST_INT32(flags); } off_t LogStart() const { return BFS_ENDIAN_TO_HOST_INT64(log_start); } off_t LogEnd() const { return BFS_ENDIAN_TO_HOST_INT64(log_end); } @@ -121,10 +124,14 @@ struct data_stream { off_t max_double_indirect_range; off_t size; - off_t MaxDirectRange() const { return BFS_ENDIAN_TO_HOST_INT64(max_direct_range); } - off_t MaxIndirectRange() const { return BFS_ENDIAN_TO_HOST_INT64(max_indirect_range); } - off_t MaxDoubleIndirectRange() const { return BFS_ENDIAN_TO_HOST_INT64(max_double_indirect_range); } - off_t Size() const { return BFS_ENDIAN_TO_HOST_INT64(size); } + off_t MaxDirectRange() const + { return BFS_ENDIAN_TO_HOST_INT64(max_direct_range); } + off_t MaxIndirectRange() const + { return BFS_ENDIAN_TO_HOST_INT64(max_indirect_range); } + off_t MaxDoubleIndirectRange() const + { return BFS_ENDIAN_TO_HOST_INT64(max_double_indirect_range); } + off_t Size() const + { return BFS_ENDIAN_TO_HOST_INT64(size); } } _PACKED; // This defines the size of the indirect and double indirect @@ -168,6 +175,13 @@ class Volume; #define SHORT_SYMLINK_NAME_LENGTH 144 // length incl. terminating '\0' +#define INODE_MAGIC1 0x3bbe0ad9 +#define INODE_FILE_NAME_LENGTH 256 +#define INODE_TIME_SHIFT 16 +#define INODE_TIME_MASK 0xffff + +inline uint32 unique_from_nsec(uint32 time); + struct bfs_inode { int32 magic1; inode_addr inode_num; @@ -175,8 +189,8 @@ struct bfs_inode { int32 gid; int32 mode; // see sys/stat.h int32 flags; - bigtime_t create_time; - bigtime_t last_modified_time; + int64 create_time; + int64 last_modified_time; inode_addr parent; inode_addr attributes; uint32 type; // attribute type @@ -201,22 +215,29 @@ struct bfs_inode { int32 Flags() const { return BFS_ENDIAN_TO_HOST_INT32(flags); } int32 Type() const { return BFS_ENDIAN_TO_HOST_INT32(type); } int32 InodeSize() const { return BFS_ENDIAN_TO_HOST_INT32(inode_size); } - bigtime_t LastModifiedTime() const { - return BFS_ENDIAN_TO_HOST_INT64(last_modified_time); } - bigtime_t CreateTime() const { - return BFS_ENDIAN_TO_HOST_INT64(create_time); } - small_data *SmallDataStart() { return small_data_start; } - bigtime_t StatusChangeTime() const { - return BFS_ENDIAN_TO_HOST_INT64(status_change_time); } + int64 LastModifiedTime() const + { return BFS_ENDIAN_TO_HOST_INT64(last_modified_time); } + int64 CreateTime() const + { return BFS_ENDIAN_TO_HOST_INT64(create_time); } + int64 StatusChangeTime() const + { return BFS_ENDIAN_TO_HOST_INT64(status_change_time); } + small_data* SmallDataStart() { return small_data_start; } status_t InitCheck(Volume *volume); // defined in Inode.cpp -} _PACKED; -#define INODE_MAGIC1 0x3bbe0ad9 -#define INODE_TIME_SHIFT 16 -#define INODE_TIME_MASK 0xffff -#define INODE_FILE_NAME_LENGTH 256 + static int64 ToInode(bigtime_t time) + { return ((time / 1000000) << INODE_TIME_SHIFT) + + unique_from_nsec((time % 1000000) * 1000); } + static int64 ToInode(const timespec& tv) + { return ((int64)tv.tv_sec << INODE_TIME_SHIFT) + + unique_from_nsec(tv.tv_nsec); } + + static time_t ToSecs(bigtime_t time) + { return time >> INODE_TIME_SHIFT; } + static uint32 ToUsecs(bigtime_t time) + { return (time & INODE_TIME_MASK) << 14; } +} _PACKED; enum inode_flags { INODE_IN_USE = 0x00000001, // always set @@ -235,6 +256,7 @@ enum inode_flags { INODE_DONT_FREE_SPACE = 0x00080000 }; + //************************************** struct file_cookie { @@ -252,6 +274,24 @@ struct file_cookie { //************************************** +/*! Converts the nano seconds given to the internal 16 bit resolution that + BFS uses. If \a time is zero, 12 bits will get a monotonically increasing + number. For all other values, only the lower 4 bits are changed this way. + + This is done to decrease the number of duplicate time values, which speeds + up the way BFS handles the time indices. +*/ +inline uint32 +unique_from_nsec(uint32 time) +{ + static vint32 number; + if (time != 0) + return ((time >> 14) & INODE_TIME_MASK) | (++number & 0xf); + + return ++number & 0xfff; +} + + inline int32 divide_roundup(int32 num,int32 divisor) { diff --git a/src/add-ons/kernel/file_systems/bfs/kernel_interface.cpp b/src/add-ons/kernel/file_systems/bfs/kernel_interface.cpp index d3bd652882..d6e8f5d1f0 100644 --- a/src/add-ons/kernel/file_systems/bfs/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/bfs/kernel_interface.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2001-2008, Axel Dörfler, axeld@pinc-software.de. + * Copyright 2001-2009, Axel Dörfler, axeld@pinc-software.de. * This file may be used under the terms of the MIT License. */ @@ -31,6 +31,34 @@ struct identify_cookie { extern void fill_stat_buffer(Inode* inode, struct stat& stat); +static void +fill_stat_time(const bfs_inode& node, struct stat& stat) +{ + stat.st_atim.tv_sec = real_time_clock(); + stat.st_atim.tv_nsec = real_time_clock_usecs() % 1000000; + + stat.st_mtim.tv_sec = bfs_inode::ToSecs(node.LastModifiedTime()); + stat.st_mtim.tv_nsec = bfs_inode::ToUsecs(node.LastModifiedTime()); + stat.st_crtim.tv_sec = bfs_inode::ToSecs(node.CreateTime()); + stat.st_crtim.tv_nsec = bfs_inode::ToUsecs(node.CreateTime()); + + // if on-disk ctime is invalid (pointer value from previous [ab]use of + // the first 4 bytes) or 0, fall back to mtime: + // N.B.: This has the drawback that explicitly setting a ctime of 0 + // will not work, but I suppose no one will do that, since ctime + // is usually just set to the current time whenever something happens + // to the inode. + // TODO: find out if this sanity check should be dropped! + bigtime_t changeTime = node.StatusChangeTime(); + if (((uint64)changeTime & 0xFFFF00000000FFFFULL) != 0 || changeTime == 0) + stat.st_ctim = stat.st_mtim; + else { + stat.st_ctim.tv_sec = bfs_inode::ToSecs(changeTime); + stat.st_ctim.tv_nsec = bfs_inode::ToUsecs(changeTime); + } +} + + void fill_stat_buffer(Inode* inode, struct stat& stat) { @@ -46,22 +74,7 @@ fill_stat_buffer(Inode* inode, struct stat& stat) stat.st_mode = node.Mode(); stat.st_type = node.Type(); - stat.st_atime = time(NULL); - stat.st_mtime = (time_t)(node.LastModifiedTime() >> INODE_TIME_SHIFT); - stat.st_crtime = (time_t)(node.CreateTime() >> INODE_TIME_SHIFT); - - // if on-disk ctime is invalid (pointer value from previous [ab]use of - // the first 4 bytes) or 0, fall back to mtime: - // N.B.: This has the drawback that explicitly setting a ctime of 0 - // will not work, but I suppose no one will do that, since ctime - // is usually just set to the current time whenever something happens - // to the inode. - // TODO: find out if this sanity check should be dropped! - bigtime_t ctime = node.StatusChangeTime(); - if (((uint64)ctime & 0xFFFF00000000FFFFULL) != 0 || ctime == 0) - stat.st_ctime = stat.st_mtime; - else - stat.st_ctime = (time_t)(ctime >> INODE_TIME_SHIFT); + fill_stat_time(node, stat); if (inode->IsSymLink() && (inode->Flags() & INODE_LONG_SYMLINK) == 0) { // symlinks report the size of the link here @@ -786,7 +799,8 @@ bfs_write_stat(fs_volume* _volume, fs_vnode* _node, const struct stat* stat, } if ((mask & B_STAT_MODE) != 0) { - PRINT(("original mode = %ld, stat->st_mode = %d\n", node.Mode(), stat->st_mode)); + PRINT(("original mode = %ld, stat->st_mode = %d\n", node.Mode(), + stat->st_mode)); node.mode = HOST_ENDIAN_TO_BFS_INT32((node.Mode() & ~S_IUMSK) | (stat->st_mode & S_IUMSK)); updateTime = true; @@ -804,27 +818,27 @@ bfs_write_stat(fs_volume* _volume, fs_vnode* _node, const struct stat* stat, if ((mask & B_STAT_MODIFICATION_TIME) != 0) { if (!inode->InLastModifiedIndex()) { // directory modification times are not part of the index - node.last_modified_time = HOST_ENDIAN_TO_BFS_INT64( - (bigtime_t)stat->st_mtime << INODE_TIME_SHIFT); + node.last_modified_time + = HOST_ENDIAN_TO_BFS_INT64(bfs_inode::ToInode(stat->st_mtim)); } else if (!inode->IsDeleted()) { // Index::UpdateLastModified() will set the new time in the inode Index index(volume); index.UpdateLastModified(transaction, inode, - (bigtime_t)stat->st_mtime << INODE_TIME_SHIFT); + bfs_inode::ToInode(stat->st_mtim)); } } if ((mask & B_STAT_CREATION_TIME) != 0) { - node.create_time = HOST_ENDIAN_TO_BFS_INT64( - (bigtime_t)stat->st_crtime << INODE_TIME_SHIFT); + node.create_time + = HOST_ENDIAN_TO_BFS_INT64(bfs_inode::ToInode(stat->st_crtim)); } if ((mask & B_STAT_CHANGE_TIME) != 0 || updateTime) { bigtime_t newTime; if ((mask & B_STAT_CHANGE_TIME) == 0) - newTime = (bigtime_t)time(NULL); + newTime = bfs_inode::ToInode(real_time_clock_usecs()); else - newTime = (bigtime_t)stat->st_ctime; - node.status_change_time - = HOST_ENDIAN_TO_BFS_INT64(newTime << INODE_TIME_SHIFT); + newTime = bfs_inode::ToInode(stat->st_ctim); + + node.status_change_time = HOST_ENDIAN_TO_BFS_INT64(newTime); } status = inode->WriteBack(transaction); @@ -841,7 +855,8 @@ status_t bfs_create(fs_volume* _volume, fs_vnode* _directory, const char* name, int openMode, int mode, void** _cookie, ino_t* _vnodeID) { - FUNCTION_START(("name = \"%s\", perms = %d, openMode = %d\n", name, mode, openMode)); + FUNCTION_START(("name = \"%s\", perms = %d, openMode = %d\n", name, mode, + openMode)); Volume* volume = (Volume*)_volume->private_volume; Inode* directory = (Inode*)_directory->private_node; @@ -2037,19 +2052,18 @@ bfs_stat_index(fs_volume* _volume, const char* name, struct stat* stat) bfs_inode& node = index.Node()->Node(); stat->st_type = index.Type(); - stat->st_size = node.data.Size(); stat->st_mode = node.Mode(); + stat->st_size = node.data.Size(); + stat->st_blocks = index.Node()->AllocatedSize() / 512; + stat->st_nlink = 1; stat->st_blksize = 65536; stat->st_uid = node.UserID(); stat->st_gid = node.GroupID(); - stat->st_atime = time(NULL); - stat->st_mtime = (time_t)(node.LastModifiedTime() >> INODE_TIME_SHIFT); - stat->st_ctime = (time_t)(node.StatusChangeTime() >> INODE_TIME_SHIFT); - stat->st_crtime = (time_t)(node.CreateTime() >> INODE_TIME_SHIFT); + fill_stat_time(node, *stat); return B_OK; }