* Some index updating functions did not take into account that not all nodes

are put into all indices. For example, symlinks aren't part of the size
  index. This fixes bug #2704.
* Also, Inode::NeedsTrimming() now ignores symlinks that have no data stream,
  it's const now, too.
* Added helper methods Inode::In{Name|Size|LastModified}Index(), and use it
  where appropriate.
* Clarified Inode::Create() description with regards to name vs. parent.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@27471 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2008-09-13 09:47:55 +00:00
parent bdff2c8222
commit 57b9debf76
4 changed files with 77 additions and 39 deletions
@@ -321,7 +321,7 @@ Index::UpdateName(Transaction &transaction, const char* oldName,
status_t status_t
Index::InsertSize(Transaction &transaction, Inode* inode) Index::InsertSize(Transaction &transaction, Inode* inode)
{ {
ASSERT(inode->IsFile()); ASSERT(inode->InSizeIndex());
off_t size = inode->Size(); off_t size = inode->Size();
return Update(transaction, "size", B_INT64_TYPE, NULL, 0, (uint8*)&size, return Update(transaction, "size", B_INT64_TYPE, NULL, 0, (uint8*)&size,
@@ -332,7 +332,7 @@ Index::InsertSize(Transaction &transaction, Inode* inode)
status_t status_t
Index::RemoveSize(Transaction &transaction, Inode* inode) Index::RemoveSize(Transaction &transaction, Inode* inode)
{ {
ASSERT(inode->IsFile()); ASSERT(inode->InSizeIndex());
// Inode::OldSize() is the size that's in the index // Inode::OldSize() is the size that's in the index
off_t size = inode->OldSize(); off_t size = inode->OldSize();
@@ -344,7 +344,7 @@ Index::RemoveSize(Transaction &transaction, Inode* inode)
status_t status_t
Index::UpdateSize(Transaction &transaction, Inode* inode) Index::UpdateSize(Transaction &transaction, Inode* inode)
{ {
ASSERT(inode->IsFile()); ASSERT(inode->InSizeIndex());
off_t oldSize = inode->OldSize(); off_t oldSize = inode->OldSize();
off_t newSize = inode->Size(); off_t newSize = inode->Size();
@@ -362,7 +362,7 @@ Index::UpdateSize(Transaction &transaction, Inode* inode)
status_t status_t
Index::InsertLastModified(Transaction &transaction, Inode* inode) Index::InsertLastModified(Transaction &transaction, Inode* inode)
{ {
ASSERT(inode->IsFile() || inode->IsSymLink()); ASSERT(inode->InLastModifiedIndex());
off_t modified = inode->LastModified(); off_t modified = inode->LastModified();
return Update(transaction, "last_modified", B_INT64_TYPE, NULL, 0, return Update(transaction, "last_modified", B_INT64_TYPE, NULL, 0,
@@ -373,7 +373,7 @@ Index::InsertLastModified(Transaction &transaction, Inode* inode)
status_t status_t
Index::RemoveLastModified(Transaction &transaction, Inode* inode) Index::RemoveLastModified(Transaction &transaction, Inode* inode)
{ {
ASSERT(inode->IsFile() || inode->IsSymLink()); ASSERT(inode->InLastModifiedIndex());
// Inode::OldLastModified() is the value which is in the index // Inode::OldLastModified() is the value which is in the index
off_t modified = inode->OldLastModified(); off_t modified = inode->OldLastModified();
@@ -386,7 +386,7 @@ status_t
Index::UpdateLastModified(Transaction &transaction, Inode* inode, Index::UpdateLastModified(Transaction &transaction, Inode* inode,
off_t modified) off_t modified)
{ {
ASSERT(inode->IsFile() || inode->IsSymLink()); ASSERT(inode->InLastModifiedIndex());
off_t oldModified = inode->OldLastModified(); off_t oldModified = inode->OldLastModified();
if (modified == -1) if (modified == -1)
+43 -19
View File
@@ -2063,18 +2063,19 @@ Inode::Append(Transaction& transaction, off_t bytes)
} }
/*! Checks wether or not this inode's data stream needs to be trimmed /*! Checks whether or not this inode's data stream needs to be trimmed
because of an earlier preallocation. because of an earlier preallocation.
Returns true if there are any blocks to be trimmed. Returns true if there are any blocks to be trimmed.
*/ */
bool bool
Inode::NeedsTrimming() Inode::NeedsTrimming() const
{ {
// We never trim preallocated index blocks to make them grow as smooth as // We never trim preallocated index blocks to make them grow as smooth as
// possible. There are only few indices anyway, so this doesn't hurt. // possible. There are only few indices anyway, so this doesn't hurt.
// Also, if an inode is already in deleted state, we don't bother trimming // Also, if an inode is already in deleted state, we don't bother trimming
// it. // it.
if (IsIndex() || IsDeleted()) if (IsIndex() || IsDeleted()
|| (IsSymLink() && (Flags() & INODE_LONG_SYMLINK) == 0))
return false; return false;
off_t roundedSize = round_up(Size(), fVolume->BlockSize()); off_t roundedSize = round_up(Size(), fVolume->BlockSize());
@@ -2301,36 +2302,36 @@ Inode::Remove(Transaction& transaction, const char* name, ino_t* _id,
// are updated here (name, size, & last_modified) // are updated here (name, size, & last_modified)
Index index(fVolume); Index index(fVolume);
if (inode->IsRegularNode()) { if (inode->InNameIndex()) {
index.RemoveName(transaction, name, inode); index.RemoveName(transaction, name, inode);
// If removing from the index fails, it is not regarded as a // If removing from the index fails, it is not regarded as a
// fatal error and will not be reported back! // fatal error and will not be reported back!
// Deleted inodes won't be visible in queries anyway. // Deleted inodes won't be visible in queries anyway.
} }
if (inode->IsFile() || inode->IsSymLink()) { if (inode->InSizeIndex())
if (inode->IsFile())
index.RemoveSize(transaction, inode); index.RemoveSize(transaction, inode);
if (inode->InLastModifiedIndex())
index.RemoveLastModified(transaction, inode); index.RemoveLastModified(transaction, inode);
}
return inode->WriteBack(transaction); return inode->WriteBack(transaction);
} }
/*! Creates the inode with the specified parent directory, and automatically /*! Creates the inode with the specified \a parent directory, and automatically
adds the created inode to that parent directory. If an attribute directory adds the created inode to that parent directory. If an attribute directory
is created, it will also automatically be added to the parent inode as is created, it will also automatically be added to the \a parent inode as
such. However, the indices root node, and the regular root node won't be such. However, the indices root node, and the regular root node won't be
added to the super block. added to the super block.
It will also create the initial B+tree for the inode if it's a directory It will also create the initial B+tree for the inode if it's a directory
of any kind. of any kind.
\a name may be \c NULL, but only if no \a parent is given.
If the "_id" or "_inode" variable is given and non-NULL to store the If the "_id" or "_inode" variable is given and non-NULL to store the
inode's ID, the inode stays locked - you have to call put_vnode() if you inode's ID, the inode stays locked - you have to call put_vnode() if you
don't use it anymore. don't use it anymore.
If the node already exists, this method will fail if O_EXCL is set, or it's If the node already exists, this method will fail if \c O_EXCL is set, or
a directory or a symlink. Otherwise, it will just be returned. If O_TRUNC it's a directory or a symlink. Otherwise, it will just be returned.
has been specified, the file will also be truncated. If \c O_TRUNC has been specified, the file will also be truncated.
*/ */
status_t status_t
Inode::Create(Transaction& transaction, Inode* parent, const char* name, Inode::Create(Transaction& transaction, Inode* parent, const char* name,
@@ -2495,7 +2496,7 @@ Inode::Create(Transaction& transaction, Inode* parent, const char* name,
// (live queries might want to access us after this) // (live queries might want to access us after this)
Index index(volume); Index index(volume);
if (inode->IsRegularNode() && name != NULL) { if (inode->InNameIndex() && name != NULL) {
// the name index only contains regular files // the name index only contains regular files
// (but not the root node where name == NULL) // (but not the root node where name == NULL)
status = index.InsertName(transaction, name, inode); status = index.InsertName(transaction, name, inode);
@@ -2514,14 +2515,13 @@ Inode::Create(Transaction& transaction, Inode* parent, const char* name,
inode->UpdateOldLastModified(); inode->UpdateOldLastModified();
// The "size" & "last_modified" indices don't contain directories // The "size" & "last_modified" indices don't contain directories.
if (inode->IsFile() || inode->IsSymLink()) { // If adding to these indices fails, the inode creation will not be
// if adding to these indices fails, the inode creation will not be // harmed; they are considered less important than the "name" index.
// harmed; they are considered less important than the "name" index if (inode->InSizeIndex())
if (inode->IsFile())
index.InsertSize(transaction, inode); index.InsertSize(transaction, inode);
if (inode->InLastModifiedIndex())
index.InsertLastModified(transaction, inode); index.InsertLastModified(transaction, inode);
}
if (inode->IsFile() || inode->IsAttribute()) { if (inode->IsFile() || inode->IsAttribute()) {
inode->SetFileCache(file_cache_create(volume->ID(), inode->ID(), inode->SetFileCache(file_cache_create(volume->ID(), inode->ID(),
@@ -2549,6 +2549,30 @@ Inode::Create(Transaction& transaction, Inode* parent, const char* name,
} }
/*! Checks whether or not this node should be part of the name index */
bool
Inode::InNameIndex() const
{
return IsRegularNode();
}
/*! Checks whether or not this node should be part of the size index */
bool
Inode::InSizeIndex() const
{
return IsFile();
}
/*! Checks whether or not this node should be part of the last modified index */
bool
Inode::InLastModifiedIndex() const
{
return IsFile() || IsSymLink();
}
// #pragma mark - AttributeIterator // #pragma mark - AttributeIterator
+6 -1
View File
@@ -140,12 +140,13 @@ public:
status_t SetFileSize(Transaction& transaction, off_t size); status_t SetFileSize(Transaction& transaction, off_t size);
status_t Append(Transaction& transaction, off_t bytes); status_t Append(Transaction& transaction, off_t bytes);
status_t TrimPreallocation(Transaction& transaction); status_t TrimPreallocation(Transaction& transaction);
bool NeedsTrimming(); bool NeedsTrimming() const;
status_t Free(Transaction& transaction); status_t Free(Transaction& transaction);
status_t Sync(); status_t Sync();
bfs_inode& Node() { return fNode; } bfs_inode& Node() { return fNode; }
const bfs_inode& Node() const { return fNode; }
// create/remove inodes // create/remove inodes
status_t Remove(Transaction& transaction, const char* name, status_t Remove(Transaction& transaction, const char* name,
@@ -165,6 +166,10 @@ public:
off_t OldSize() { return fOldSize; } off_t OldSize() { return fOldSize; }
off_t OldLastModified() { return fOldLastModified; } off_t OldLastModified() { return fOldLastModified; }
bool InNameIndex() const;
bool InSizeIndex() const;
bool InLastModifiedIndex() const;
// file cache // file cache
void* FileCache() const { return fCache; } void* FileCache() const { return fCache; }
void SetFileCache(void* cache) { fCache = cache; } void SetFileCache(void* cache) { fCache = cache; }
@@ -723,12 +723,14 @@ bfs_write_stat(fs_volume* _volume, fs_vnode* _node, const struct stat* stat,
bfs_inode& node = inode->Node(); bfs_inode& node = inode->Node();
if (mask & B_STAT_SIZE) { if ((mask & B_STAT_SIZE) != 0) {
// Since WSTAT_SIZE is the only thing that can fail directly, we // Since WSTAT_SIZE is the only thing that can fail directly, we
// do it first, so that the inode state will still be consistent // do it first, so that the inode state will still be consistent
// with the on-disk version // with the on-disk version
if (inode->IsDirectory()) if (inode->IsDirectory())
return B_IS_A_DIRECTORY; return B_IS_A_DIRECTORY;
if (!inode->IsFile())
return B_BAD_VALUE;
if (inode->Size() != stat->st_size) { if (inode->Size() != stat->st_size) {
off_t oldSize = inode->Size(); off_t oldSize = inode->Size();
@@ -751,19 +753,19 @@ bfs_write_stat(fs_volume* _volume, fs_vnode* _node, const struct stat* stat,
} }
} }
if (mask & B_STAT_MODE) { 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) node.mode = HOST_ENDIAN_TO_BFS_INT32((node.Mode() & ~S_IUMSK)
| (stat->st_mode & S_IUMSK)); | (stat->st_mode & S_IUMSK));
} }
if (mask & B_STAT_UID) if ((mask & B_STAT_UID) != 0)
node.uid = HOST_ENDIAN_TO_BFS_INT32(stat->st_uid); node.uid = HOST_ENDIAN_TO_BFS_INT32(stat->st_uid);
if (mask & B_STAT_GID) if ((mask & B_STAT_GID) != 0)
node.gid = HOST_ENDIAN_TO_BFS_INT32(stat->st_gid); node.gid = HOST_ENDIAN_TO_BFS_INT32(stat->st_gid);
if (mask & B_STAT_MODIFICATION_TIME) { if ((mask & B_STAT_MODIFICATION_TIME) != 0) {
if (inode->IsDirectory()) { if (!inode->InLastModifiedIndex()) {
// directory modification times are not part of the index // directory modification times are not part of the index
node.last_modified_time = HOST_ENDIAN_TO_BFS_INT64( node.last_modified_time = HOST_ENDIAN_TO_BFS_INT64(
(bigtime_t)stat->st_mtime << INODE_TIME_SHIFT); (bigtime_t)stat->st_mtime << INODE_TIME_SHIFT);
@@ -774,7 +776,7 @@ bfs_write_stat(fs_volume* _volume, fs_vnode* _node, const struct stat* stat,
(bigtime_t)stat->st_mtime << INODE_TIME_SHIFT); (bigtime_t)stat->st_mtime << INODE_TIME_SHIFT);
} }
} }
if (mask & B_STAT_CREATION_TIME) { if ((mask & B_STAT_CREATION_TIME) != 0) {
node.create_time = HOST_ENDIAN_TO_BFS_INT64( node.create_time = HOST_ENDIAN_TO_BFS_INT64(
(bigtime_t)stat->st_crtime << INODE_TIME_SHIFT); (bigtime_t)stat->st_crtime << INODE_TIME_SHIFT);
} }
@@ -1296,7 +1298,10 @@ bfs_free_cookie(fs_volume* _volume, fs_vnode* _node, void* _cookie)
&& !inode->IsDeleted() && !inode->IsDeleted()
&& (needsTrimming && (needsTrimming
|| inode->OldLastModified() != inode->LastModified() || inode->OldLastModified() != inode->LastModified()
|| inode->OldSize() != inode->Size())) { || (inode->InSizeIndex()
// TODO: this can prevent the size update notification
// for nodes not in the index!
&& inode->OldSize() != inode->Size()))) {
locker.Unlock(); locker.Unlock();
transaction.Start(volume, inode->BlockNumber()); transaction.Start(volume, inode->BlockNumber());
} }
@@ -1323,11 +1328,15 @@ bfs_free_cookie(fs_volume* _volume, fs_vnode* _node, void* _cookie)
} }
} }
if (inode->OldSize() != inode->Size()) { if (inode->OldSize() != inode->Size()) {
if (inode->InSizeIndex())
index.UpdateSize(transaction, inode); index.UpdateSize(transaction, inode);
changedSize = true; changedSize = true;
} }
if (inode->OldLastModified() != inode->LastModified()) { if (inode->OldLastModified() != inode->LastModified()) {
index.UpdateLastModified(transaction, inode, inode->LastModified()); if (inode->InLastModifiedIndex()) {
index.UpdateLastModified(transaction, inode,
inode->LastModified());
}
changedTime = true; changedTime = true;
// updating the index doesn't write back the inode // updating the index doesn't write back the inode
@@ -1385,7 +1394,7 @@ bfs_read_link(fs_volume* _volume, fs_vnode* _node, char* buffer,
if (!inode->IsSymLink()) if (!inode->IsSymLink())
RETURN_ERROR(B_BAD_VALUE); RETURN_ERROR(B_BAD_VALUE);
if (inode->Flags() & INODE_LONG_SYMLINK) { if ((inode->Flags() & INODE_LONG_SYMLINK) != 0) {
if (inode->Size() < *_bufferSize) if (inode->Size() < *_bufferSize)
*_bufferSize = inode->Size(); *_bufferSize = inode->Size();