* Cleanup of how the time is converted between bfs_inode and the outside world:

there is now a couple of conversion functions, and I changed the type from
  bigtime_t to int64, as it's not what a bigtime_t would usually contain, but
  some shift magic in order to make duplicate index entries less likely.
* We now correctly fill in the timespec in struct stat as good as possible; the
  12 of the 16 possible bits are used for the nano second value. The lower 8
  bits are used to avoid the duplicate index entries. Only if the nano second
  time is 0, the lower 12 bits are used to achieve that.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@31057 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2009-06-15 09:49:12 +00:00
parent d49c767c5e
commit e494494122
7 changed files with 125 additions and 85 deletions
@@ -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());
@@ -1,5 +1,5 @@
/*
* Copyright 2001-2008, Axel Dörfler, [email protected].
* Copyright 2001-2009, Axel Dörfler, [email protected].
* 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,
+5 -10
View File
@@ -1,5 +1,5 @@
/*
* Copyright 2001-2008, Axel Dörfler, [email protected].
* Copyright 2001-2009, Axel Dörfler, [email protected].
* 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!
@@ -1,5 +1,5 @@
/*
* Copyright 2001-2008, Axel Dörfler, [email protected].
* Copyright 2001-2009, Axel Dörfler, [email protected].
* 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)
{
@@ -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<Query> 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
+61 -21
View File
@@ -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)
{
@@ -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;
}