* added support for extra inode attributes in volumes with an inodesize of 256 or more:

this brings nanoseconds for access, change and modification times, and also brings creation time.
* switched off some debug output
* HTreeEntryIterator: fCount can equal fLimit.



git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@38964 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Jérôme Duval
2010-10-13 17:17:45 +00:00
parent 14f487c4de
commit 6bfb10d312
5 changed files with 172 additions and 62 deletions
@@ -91,8 +91,9 @@ HTreeEntryIterator::Init()
fCount = countLimit->Count(); fCount = countLimit->Count();
fLimit = countLimit->Limit(); fLimit = countLimit->Limit();
if (fCount >= fLimit) { if (fCount > fLimit) {
ERROR("HTreeEntryIterator::Init() bad fCount %lu\n", (uint32)fCount); ERROR("HTreeEntryIterator::Init() bad fCount %u (fLimit %u)\n",
fCount, fLimit);
fCount = fLimit = 0; fCount = fLimit = 0;
return B_ERROR; return B_ERROR;
} }
+16 -5
View File
@@ -43,6 +43,10 @@ Inode::Inode(Volume* volume, ino_t id)
fInitStatus = UpdateNodeFromDisk(); fInitStatus = UpdateNodeFromDisk();
if (fInitStatus == B_OK) { if (fInitStatus == B_OK) {
fHasExtraAttributes = (fNodeSize == sizeof(ext2_inode)
&& fNode.ExtraInodeSize() + EXT2_INODE_NORMAL_SIZE
== sizeof(ext2_inode));
if (IsDirectory() || (IsSymLink() && Size() < 60)) { if (IsDirectory() || (IsSymLink() && Size() < 60)) {
TRACE("Inode::Inode(): Not creating the file cache\n"); TRACE("Inode::Inode(): Not creating the file cache\n");
fCached = false; fCached = false;
@@ -342,7 +346,9 @@ Inode::WriteAt(Transaction& transaction, off_t pos, const uint8* buffer,
WriteLocker writeLocker(fLock); WriteLocker writeLocker(fLock);
TRACE("Inode::WriteAt(): Updating modification time\n"); TRACE("Inode::WriteAt(): Updating modification time\n");
fNode.SetModificationTime(real_time_clock()); struct timespec timespec;
_BigtimeToTimespec(real_time_clock_usecs(), &timespec);
SetModificationTime(&timespec);
// NOTE: Debugging info to find why sometimes resize doesn't happen // NOTE: Debugging info to find why sometimes resize doesn't happen
size_t length = *_length; size_t length = *_length;
@@ -699,10 +705,14 @@ Inode::Create(Transaction& transaction, Inode* parent, const char* name,
node.SetGroupID(parent != NULL ? parent->Node().GroupID() : getegid()); node.SetGroupID(parent != NULL ? parent->Node().GroupID() : getegid());
node.SetNumLinks(inode->IsDirectory() ? 2 : 1); node.SetNumLinks(inode->IsDirectory() ? 2 : 1);
TRACE("Inode::Create(): Updating time\n"); TRACE("Inode::Create(): Updating time\n");
time_t creationTime = real_time_clock(); struct timespec timespec;
node.SetAccessTime(creationTime); _BigtimeToTimespec(real_time_clock_usecs(), &timespec);
node.SetCreationTime(creationTime); inode->SetAccessTime(&timespec);
node.SetModificationTime(creationTime); inode->SetCreationTime(&timespec);
inode->SetModificationTime(&timespec);
if (sizeof(ext2_inode) < volume->InodeSize())
node.SetExtraInodeSize(sizeof(ext2_inode) - EXT2_INODE_NORMAL_SIZE);
TRACE("Inode::Create(): Updating ID\n"); TRACE("Inode::Create(): Updating ID\n");
inode->fID = id; inode->fID = id;
@@ -963,3 +973,4 @@ Inode::_SetNumBlocks(uint64 numBlocks)
fNode.SetNumBlocks64(numBlocks); fNode.SetNumBlocks64(numBlocks);
return B_OK; return B_OK;
} }
+45 -13
View File
@@ -14,6 +14,14 @@
#include "Volume.h" #include "Volume.h"
//#define TRACE_EXT2
#ifdef TRACE_EXT2
# define TRACEI(x...) dprintf("\33[34mext2:\33[0m " x)
#else
# define TRACEI(x...) ;
#endif
class Inode : public TransactionListener { class Inode : public TransactionListener {
public: public:
Inode(Volume* volume, ino_t id); Inode(Volume* volume, ino_t id);
@@ -38,17 +46,33 @@ public:
status_t CheckPermissions(int accessMode) const; status_t CheckPermissions(int accessMode) const;
bool IsDeleted() const { return fUnlinked; } bool IsDeleted() const { return fUnlinked; }
bool HasExtraAttributes() const
{ return fHasExtraAttributes; }
mode_t Mode() const { return fNode.Mode(); } mode_t Mode() const { return fNode.Mode(); }
int32 Flags() const { return fNode.Flags(); } int32 Flags() const { return fNode.Flags(); }
off_t Size() const { return fNode.Size(); } off_t Size() const { return fNode.Size(); }
time_t ModificationTime() const void GetChangeTime(struct timespec *timespec) const
{ return fNode.ModificationTime(); } { fNode.GetChangeTime(timespec, fHasExtraAttributes); }
time_t CreationTime() const void GetModificationTime(struct timespec *timespec) const
{ return fNode.CreationTime(); } { fNode.GetModificationTime(timespec,
time_t AccessTime() const fHasExtraAttributes); }
{ return fNode.AccessTime(); } void GetCreationTime(struct timespec *timespec) const
{ fNode.GetCreationTime(timespec,
fHasExtraAttributes); }
void GetAccessTime(struct timespec *timespec) const
{ fNode.GetAccessTime(timespec, fHasExtraAttributes); }
void SetChangeTime(const struct timespec *timespec)
{ fNode.SetChangeTime(timespec, fHasExtraAttributes); }
void SetModificationTime(const struct timespec *timespec)
{ fNode.SetModificationTime(timespec,
fHasExtraAttributes); }
void SetCreationTime(const struct timespec *timespec)
{ fNode.SetCreationTime(timespec,
fHasExtraAttributes); }
void SetAccessTime(const struct timespec *timespec)
{ fNode.SetAccessTime(timespec, fHasExtraAttributes); }
//::Volume* _Volume() const { return fVolume; } //::Volume* _Volume() const { return fVolume; }
Volume* GetVolume() const { return fVolume; } Volume* GetVolume() const { return fVolume; }
@@ -76,6 +100,10 @@ public:
ino_t* _id = NULL, Inode** _inode = NULL, ino_t* _id = NULL, Inode** _inode = NULL,
fs_vnode_ops* vnodeOps = NULL, fs_vnode_ops* vnodeOps = NULL,
uint32 publishFlags = 0); uint32 publishFlags = 0);
static void _BigtimeToTimespec(bigtime_t time,
struct timespec *timespec)
{ timespec->tv_sec = time / 1000000LL;
timespec->tv_nsec = (time % 1000000LL) * 1000; }
void* FileCache() const { return fCache; } void* FileCache() const { return fCache; }
void* Map() const { return fMap; } void* Map() const { return fMap; }
@@ -85,6 +113,8 @@ public:
status_t Sync(); status_t Sync();
protected: protected:
virtual void TransactionDone(bool success); virtual void TransactionDone(bool success);
virtual void RemovedFromTransaction(); virtual void RemovedFromTransaction();
@@ -98,7 +128,8 @@ private:
status_t _EnlargeDataStream(Transaction& transaction, status_t _EnlargeDataStream(Transaction& transaction,
off_t size); off_t size);
status_t _ShrinkDataStream(Transaction& transaction, off_t size); status_t _ShrinkDataStream(Transaction& transaction,
off_t size);
uint64 _NumBlocks(); uint64 _NumBlocks();
status_t _SetNumBlocks(uint64 numBlocks); status_t _SetNumBlocks(uint64 numBlocks);
@@ -110,9 +141,10 @@ private:
void* fMap; void* fMap;
bool fCached; bool fCached;
bool fUnlinked; bool fUnlinked;
bool fHasExtraAttributes;
ext2_inode fNode; ext2_inode fNode;
uint32 fNodeSize; uint32 fNodeSize;
// Inodes have a varible size, but the important // Inodes have a variable size, but the important
// information is always the same size (except in ext4) // information is always the same size (except in ext4)
ext2_xattr_header* fAttributesBlock; ext2_xattr_header* fAttributesBlock;
status_t fInitStatus; status_t fInitStatus;
@@ -173,31 +205,31 @@ public:
void Keep() void Keep()
{ {
dprintf("Vnode::Keep()\n"); TRACEI("Vnode::Keep()\n");
fInode = NULL; fInode = NULL;
} }
status_t Publish(Transaction& transaction, Inode* inode, status_t Publish(Transaction& transaction, Inode* inode,
fs_vnode_ops* vnodeOps, uint32 publishFlags) fs_vnode_ops* vnodeOps, uint32 publishFlags)
{ {
dprintf("Vnode::Publish()\n"); TRACEI("Vnode::Publish()\n");
Volume* volume = transaction.GetVolume(); Volume* volume = transaction.GetVolume();
status_t status = B_OK; status_t status = B_OK;
if (!inode->IsSymLink() && volume->ID() >= 0) { if (!inode->IsSymLink() && volume->ID() >= 0) {
dprintf("Vnode::Publish(): Publishing vnode: %d, %d, %p, %p, %x, " TRACEI("Vnode::Publish(): Publishing vnode: %d, %d, %p, %p, %x, "
"%x\n", (int)volume->FSVolume(), (int)inode->ID(), inode, "%x\n", (int)volume->FSVolume(), (int)inode->ID(), inode,
vnodeOps != NULL ? vnodeOps : &gExt2VnodeOps, (int)inode->Mode(), vnodeOps != NULL ? vnodeOps : &gExt2VnodeOps, (int)inode->Mode(),
(int)publishFlags); (int)publishFlags);
status = publish_vnode(volume->FSVolume(), inode->ID(), inode, status = publish_vnode(volume->FSVolume(), inode->ID(), inode,
vnodeOps != NULL ? vnodeOps : &gExt2VnodeOps, inode->Mode(), vnodeOps != NULL ? vnodeOps : &gExt2VnodeOps, inode->Mode(),
publishFlags); publishFlags);
dprintf("Vnode::Publish(): Result: %s\n", strerror(status)); TRACEI("Vnode::Publish(): Result: %s\n", strerror(status));
} }
if (status == B_OK) { if (status == B_OK) {
dprintf("Vnode::Publish(): Preparing internal data\n"); TRACEI("Vnode::Publish(): Preparing internal data\n");
fInode = inode; fInode = inode;
fStatus = B_OK; fStatus = B_OK;
+91 -26
View File
@@ -210,19 +210,21 @@ struct ext2_data_stream {
uint32 triple_indirect; uint32 triple_indirect;
} _PACKED; } _PACKED;
#define EXT2_INODE_NORMAL_SIZE 128
struct ext2_inode { struct ext2_inode {
uint16 mode; uint16 mode;
uint16 uid; uint16 uid;
uint32 size; uint32 size;
uint32 access_time; uint32 access_time;
uint32 creation_time; uint32 change_time;
uint32 modification_time; uint32 modification_time;
uint32 deletion_time; uint32 deletion_time;
uint16 gid; uint16 gid;
uint16 num_links; uint16 num_links;
uint32 num_blocks; uint32 num_blocks;
uint32 flags; uint32 flags;
uint32 _reserved1; uint32 version;
union { union {
ext2_data_stream stream; ext2_data_stream stream;
char symlink[EXT2_SHORT_SYMLINK_LENGTH]; char symlink[EXT2_SHORT_SYMLINK_LENGTH];
@@ -246,8 +248,16 @@ struct ext2_inode {
uint16 uid_high; uint16 uid_high;
uint16 gid_high; uint16 gid_high;
uint32 _reserved2; uint32 _reserved2;
// extra attributes
uint16 extra_inode_size; uint16 extra_inode_size;
uint16 _padding2; uint16 _padding2;
uint32 change_time_extra;
uint32 modification_time_extra;
uint32 access_time_extra;
uint32 creation_time;
uint32 creation_time_extra;
uint32 version_high;
uint16 Mode() const { return B_LENDIAN_TO_HOST_INT16(mode); } uint16 Mode() const { return B_LENDIAN_TO_HOST_INT16(mode); }
uint32 Flags() const { return B_LENDIAN_TO_HOST_INT32(flags); } uint32 Flags() const { return B_LENDIAN_TO_HOST_INT32(flags); }
@@ -256,10 +266,77 @@ struct ext2_inode {
uint64 NumBlocks64() const { return B_LENDIAN_TO_HOST_INT32(num_blocks) uint64 NumBlocks64() const { return B_LENDIAN_TO_HOST_INT32(num_blocks)
| ((uint64)B_LENDIAN_TO_HOST_INT32(num_blocks_high) << 32); } | ((uint64)B_LENDIAN_TO_HOST_INT32(num_blocks_high) << 32); }
time_t AccessTime() const { return B_LENDIAN_TO_HOST_INT32(access_time); } static void _DecodeTime(struct timespec *timespec, uint32 time,
time_t CreationTime() const { return B_LENDIAN_TO_HOST_INT32(creation_time); } uint32 time_extra, bool extra)
time_t ModificationTime() const { return B_LENDIAN_TO_HOST_INT32(modification_time); } {
time_t DeletionTime() const { return B_LENDIAN_TO_HOST_INT32(deletion_time); } timespec->tv_sec = B_LENDIAN_TO_HOST_INT32(time);
if (extra && sizeof(timespec->tv_sec) > 4)
timespec->tv_sec |=
(uint64)(B_LENDIAN_TO_HOST_INT32(time_extra) & 0x2) << 32;
if (extra)
timespec->tv_nsec = B_LENDIAN_TO_HOST_INT32(time_extra) >> 2;
else
timespec->tv_nsec = 0;
}
void GetModificationTime(struct timespec *timespec, bool extra) const
{ _DecodeTime(timespec, modification_time, modification_time_extra,
extra); }
void GetAccessTime(struct timespec *timespec, bool extra) const
{ _DecodeTime(timespec, access_time, access_time_extra, extra); }
void GetChangeTime(struct timespec *timespec, bool extra) const
{ _DecodeTime(timespec, change_time, change_time_extra, extra); }
void GetCreationTime(struct timespec *timespec, bool extra) const
{
if (extra)
_DecodeTime(timespec, creation_time, creation_time_extra, extra);
else {
timespec->tv_sec = 0;
timespec->tv_nsec = 0;
}
}
time_t DeletionTime() const
{ return B_LENDIAN_TO_HOST_INT32(deletion_time); }
static uint32 _EncodeTime(const struct timespec *timespec)
{
uint32 time = (timespec->tv_nsec << 2) & 0xfffffffc;
if (sizeof(timespec->tv_sec) > 4)
time |= (uint64)timespec->tv_sec >> 32;
return B_HOST_TO_LENDIAN_INT32(time);
}
void SetModificationTime(const struct timespec *timespec, bool extra)
{
modification_time = B_HOST_TO_LENDIAN_INT32((uint32)timespec->tv_sec);
if (extra)
modification_time_extra = _EncodeTime(timespec);
}
void SetAccessTime(const struct timespec *timespec, bool extra)
{
access_time = B_HOST_TO_LENDIAN_INT32((uint32)timespec->tv_sec);
if (extra)
access_time_extra = _EncodeTime(timespec);
}
void SetChangeTime(const struct timespec *timespec, bool extra)
{
change_time = B_HOST_TO_LENDIAN_INT32((uint32)timespec->tv_sec);
if (extra)
change_time_extra = _EncodeTime(timespec);
}
void SetCreationTime(const struct timespec *timespec, bool extra)
{
if (extra) {
creation_time = B_HOST_TO_LENDIAN_INT32((uint32)timespec->tv_sec);
creation_time_extra =
B_HOST_TO_LENDIAN_INT32((uint32)timespec->tv_nsec);
}
}
void SetDeletionTime(time_t deletionTime)
{
deletion_time = B_HOST_TO_LENDIAN_INT32((uint32)deletionTime);
}
ino_t NextOrphan() const { return (ino_t)DeletionTime(); } ino_t NextOrphan() const { return (ino_t)DeletionTime(); }
off_t Size() const off_t Size() const
@@ -272,6 +349,9 @@ struct ext2_inode {
return B_LENDIAN_TO_HOST_INT32(size); return B_LENDIAN_TO_HOST_INT32(size);
} }
uint16 ExtraInodeSize() const
{ return B_LENDIAN_TO_HOST_INT16(extra_inode_size); }
uint32 UserID() const uint32 UserID() const
{ {
return B_LENDIAN_TO_HOST_INT16(uid) return B_LENDIAN_TO_HOST_INT16(uid)
@@ -325,26 +405,6 @@ struct ext2_inode {
num_blocks_high = B_HOST_TO_LENDIAN_INT32(numBlocks >> 32); num_blocks_high = B_HOST_TO_LENDIAN_INT32(numBlocks >> 32);
} }
void SetAccessTime(time_t accessTime)
{
access_time = B_HOST_TO_LENDIAN_INT32((uint32)accessTime);
}
void SetCreationTime(time_t creationTime)
{
creation_time = B_HOST_TO_LENDIAN_INT32((uint32)creationTime);
}
void SetModificationTime(time_t modificationTime)
{
modification_time = B_HOST_TO_LENDIAN_INT32((uint32)modificationTime);
}
void SetDeletionTime(time_t deletionTime)
{
deletion_time = B_HOST_TO_LENDIAN_INT32((uint32)deletionTime);
}
void SetNextOrphan(ino_t id) void SetNextOrphan(ino_t id)
{ {
deletion_time = B_HOST_TO_LENDIAN_INT32((uint32)id); deletion_time = B_HOST_TO_LENDIAN_INT32((uint32)id);
@@ -373,6 +433,11 @@ struct ext2_inode {
{ {
file_access_control = B_HOST_TO_LENDIAN_INT32(block); file_access_control = B_HOST_TO_LENDIAN_INT32(block);
} }
void SetExtraInodeSize(uint16 newSize)
{
extra_inode_size = B_HOST_TO_LENDIAN_INT16(newSize);
}
} _PACKED; } _PACKED;
#define EXT2_SUPER_BLOCK_MAGIC 0xef53 #define EXT2_SUPER_BLOCK_MAGIC 0xef53
@@ -550,9 +550,10 @@ ext2_read_stat(fs_volume* _volume, fs_vnode* _node, struct stat* stat)
stat->st_mode = node.Mode(); stat->st_mode = node.Mode();
stat->st_type = 0; stat->st_type = 0;
stat->st_atime = node.AccessTime(); inode->GetAccessTime(&stat->st_atim);
stat->st_mtime = stat->st_ctime = node.ModificationTime(); inode->GetModificationTime(&stat->st_mtim);
stat->st_crtime = node.CreationTime(); inode->GetChangeTime(&stat->st_ctim);
inode->GetCreationTime(&stat->st_crtim);
stat->st_size = inode->Size(); stat->st_size = inode->Size();
stat->st_blocks = (inode->Size() + 511) / 512; stat->st_blocks = (inode->Size() + 511) / 512;
@@ -626,22 +627,22 @@ ext2_write_stat(fs_volume* _volume, fs_vnode* _node, const struct stat* stat,
if ((mask & B_STAT_MODIFICATION_TIME) != 0 || updateTime if ((mask & B_STAT_MODIFICATION_TIME) != 0 || updateTime
|| (mask & B_STAT_CHANGE_TIME) != 0) { || (mask & B_STAT_CHANGE_TIME) != 0) {
time_t newTime = 0; struct timespec newTimespec = { 0, 0};
if ((mask & B_STAT_MODIFICATION_TIME) != 0) if ((mask & B_STAT_MODIFICATION_TIME) != 0)
newTime = stat->st_mtim.tv_sec; newTimespec = stat->st_mtim;
if ((mask & B_STAT_CHANGE_TIME) != 0) if ((mask & B_STAT_CHANGE_TIME) != 0
newTime = newTime > stat->st_ctim.tv_sec ? newTime && stat->st_ctim.tv_sec > newTimespec.tv_sec)
: stat->st_ctim.tv_sec; newTimespec = stat->st_ctim;
if (newTime == 0) if (newTimespec.tv_sec == 0)
newTime = real_time_clock(); Inode::_BigtimeToTimespec(real_time_clock_usecs(), &newTimespec);
node.SetModificationTime(newTime); inode->SetModificationTime(&newTimespec);
} }
if ((mask & B_STAT_CREATION_TIME) != 0) if ((mask & B_STAT_CREATION_TIME) != 0)
node.SetCreationTime(stat->st_crtim.tv_sec); inode->SetCreationTime(&stat->st_crtim);
status = inode->WriteBack(transaction); status = inode->WriteBack(transaction);
if (status == B_OK) if (status == B_OK)