* 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();
fLimit = countLimit->Limit();
if (fCount >= fLimit) {
ERROR("HTreeEntryIterator::Init() bad fCount %lu\n", (uint32)fCount);
if (fCount > fLimit) {
ERROR("HTreeEntryIterator::Init() bad fCount %u (fLimit %u)\n",
fCount, fLimit);
fCount = fLimit = 0;
return B_ERROR;
}
+16 -5
View File
@@ -43,6 +43,10 @@ Inode::Inode(Volume* volume, ino_t id)
fInitStatus = UpdateNodeFromDisk();
if (fInitStatus == B_OK) {
fHasExtraAttributes = (fNodeSize == sizeof(ext2_inode)
&& fNode.ExtraInodeSize() + EXT2_INODE_NORMAL_SIZE
== sizeof(ext2_inode));
if (IsDirectory() || (IsSymLink() && Size() < 60)) {
TRACE("Inode::Inode(): Not creating the file cache\n");
fCached = false;
@@ -342,7 +346,9 @@ Inode::WriteAt(Transaction& transaction, off_t pos, const uint8* buffer,
WriteLocker writeLocker(fLock);
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
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.SetNumLinks(inode->IsDirectory() ? 2 : 1);
TRACE("Inode::Create(): Updating time\n");
time_t creationTime = real_time_clock();
node.SetAccessTime(creationTime);
node.SetCreationTime(creationTime);
node.SetModificationTime(creationTime);
struct timespec timespec;
_BigtimeToTimespec(real_time_clock_usecs(), &timespec);
inode->SetAccessTime(&timespec);
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");
inode->fID = id;
@@ -963,3 +973,4 @@ Inode::_SetNumBlocks(uint64 numBlocks)
fNode.SetNumBlocks64(numBlocks);
return B_OK;
}
+47 -15
View File
@@ -14,6 +14,14 @@
#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 {
public:
Inode(Volume* volume, ino_t id);
@@ -38,17 +46,33 @@ public:
status_t CheckPermissions(int accessMode) const;
bool IsDeleted() const { return fUnlinked; }
bool HasExtraAttributes() const
{ return fHasExtraAttributes; }
mode_t Mode() const { return fNode.Mode(); }
int32 Flags() const { return fNode.Flags(); }
off_t Size() const { return fNode.Size(); }
time_t ModificationTime() const
{ return fNode.ModificationTime(); }
time_t CreationTime() const
{ return fNode.CreationTime(); }
time_t AccessTime() const
{ return fNode.AccessTime(); }
void GetChangeTime(struct timespec *timespec) const
{ fNode.GetChangeTime(timespec, fHasExtraAttributes); }
void GetModificationTime(struct timespec *timespec) const
{ fNode.GetModificationTime(timespec,
fHasExtraAttributes); }
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* GetVolume() const { return fVolume; }
@@ -76,7 +100,11 @@ public:
ino_t* _id = NULL, Inode** _inode = NULL,
fs_vnode_ops* vnodeOps = NULL,
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* Map() const { return fMap; }
status_t EnableFileCache();
@@ -85,6 +113,8 @@ public:
status_t Sync();
protected:
virtual void TransactionDone(bool success);
virtual void RemovedFromTransaction();
@@ -98,8 +128,9 @@ private:
status_t _EnlargeDataStream(Transaction& transaction,
off_t size);
status_t _ShrinkDataStream(Transaction& transaction, off_t size);
status_t _ShrinkDataStream(Transaction& transaction,
off_t size);
uint64 _NumBlocks();
status_t _SetNumBlocks(uint64 numBlocks);
@@ -110,9 +141,10 @@ private:
void* fMap;
bool fCached;
bool fUnlinked;
bool fHasExtraAttributes;
ext2_inode fNode;
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)
ext2_xattr_header* fAttributesBlock;
status_t fInitStatus;
@@ -173,31 +205,31 @@ public:
void Keep()
{
dprintf("Vnode::Keep()\n");
TRACEI("Vnode::Keep()\n");
fInode = NULL;
}
status_t Publish(Transaction& transaction, Inode* inode,
fs_vnode_ops* vnodeOps, uint32 publishFlags)
{
dprintf("Vnode::Publish()\n");
TRACEI("Vnode::Publish()\n");
Volume* volume = transaction.GetVolume();
status_t status = B_OK;
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,
vnodeOps != NULL ? vnodeOps : &gExt2VnodeOps, (int)inode->Mode(),
(int)publishFlags);
status = publish_vnode(volume->FSVolume(), inode->ID(), inode,
vnodeOps != NULL ? vnodeOps : &gExt2VnodeOps, inode->Mode(),
publishFlags);
dprintf("Vnode::Publish(): Result: %s\n", strerror(status));
TRACEI("Vnode::Publish(): Result: %s\n", strerror(status));
}
if (status == B_OK) {
dprintf("Vnode::Publish(): Preparing internal data\n");
TRACEI("Vnode::Publish(): Preparing internal data\n");
fInode = inode;
fStatus = B_OK;
+92 -27
View File
@@ -210,19 +210,21 @@ struct ext2_data_stream {
uint32 triple_indirect;
} _PACKED;
#define EXT2_INODE_NORMAL_SIZE 128
struct ext2_inode {
uint16 mode;
uint16 uid;
uint32 size;
uint32 access_time;
uint32 creation_time;
uint32 change_time;
uint32 modification_time;
uint32 deletion_time;
uint16 gid;
uint16 num_links;
uint32 num_blocks;
uint32 flags;
uint32 _reserved1;
uint32 version;
union {
ext2_data_stream stream;
char symlink[EXT2_SHORT_SYMLINK_LENGTH];
@@ -246,8 +248,16 @@ struct ext2_inode {
uint16 uid_high;
uint16 gid_high;
uint32 _reserved2;
// extra attributes
uint16 extra_inode_size;
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); }
uint32 Flags() const { return B_LENDIAN_TO_HOST_INT32(flags); }
@@ -256,12 +266,79 @@ struct ext2_inode {
uint64 NumBlocks64() const { return B_LENDIAN_TO_HOST_INT32(num_blocks)
| ((uint64)B_LENDIAN_TO_HOST_INT32(num_blocks_high) << 32); }
time_t AccessTime() const { return B_LENDIAN_TO_HOST_INT32(access_time); }
time_t CreationTime() const { return B_LENDIAN_TO_HOST_INT32(creation_time); }
time_t ModificationTime() const { return B_LENDIAN_TO_HOST_INT32(modification_time); }
time_t DeletionTime() const { return B_LENDIAN_TO_HOST_INT32(deletion_time); }
ino_t NextOrphan() const { return (ino_t)DeletionTime(); }
static void _DecodeTime(struct timespec *timespec, uint32 time,
uint32 time_extra, bool extra)
{
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(); }
off_t Size() const
{
if (S_ISREG(Mode())) {
@@ -272,6 +349,9 @@ struct ext2_inode {
return B_LENDIAN_TO_HOST_INT32(size);
}
uint16 ExtraInodeSize() const
{ return B_LENDIAN_TO_HOST_INT16(extra_inode_size); }
uint32 UserID() const
{
return B_LENDIAN_TO_HOST_INT16(uid)
@@ -325,26 +405,6 @@ struct ext2_inode {
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)
{
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);
}
void SetExtraInodeSize(uint16 newSize)
{
extra_inode_size = B_HOST_TO_LENDIAN_INT16(newSize);
}
} _PACKED;
#define EXT2_SUPER_BLOCK_MAGIC 0xef53
@@ -550,10 +550,11 @@ ext2_read_stat(fs_volume* _volume, fs_vnode* _node, struct stat* stat)
stat->st_mode = node.Mode();
stat->st_type = 0;
stat->st_atime = node.AccessTime();
stat->st_mtime = stat->st_ctime = node.ModificationTime();
stat->st_crtime = node.CreationTime();
inode->GetAccessTime(&stat->st_atim);
inode->GetModificationTime(&stat->st_mtim);
inode->GetChangeTime(&stat->st_ctim);
inode->GetCreationTime(&stat->st_crtim);
stat->st_size = inode->Size();
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
|| (mask & B_STAT_CHANGE_TIME) != 0) {
time_t newTime = 0;
struct timespec newTimespec = { 0, 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)
newTime = newTime > stat->st_ctim.tv_sec ? newTime
: stat->st_ctim.tv_sec;
if ((mask & B_STAT_CHANGE_TIME) != 0
&& stat->st_ctim.tv_sec > newTimespec.tv_sec)
newTimespec = stat->st_ctim;
if (newTime == 0)
newTime = real_time_clock();
if (newTimespec.tv_sec == 0)
Inode::_BigtimeToTimespec(real_time_clock_usecs(), &newTimespec);
node.SetModificationTime(newTime);
inode->SetModificationTime(&newTimespec);
}
if ((mask & B_STAT_CREATION_TIME) != 0)
node.SetCreationTime(stat->st_crtim.tv_sec);
inode->SetCreationTime(&stat->st_crtim);
status = inode->WriteBack(transaction);
if (status == B_OK)