* 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:
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user