* 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
Index::InsertSize(Transaction &transaction, Inode* inode)
{
ASSERT(inode->IsFile());
ASSERT(inode->InSizeIndex());
off_t size = inode->Size();
return Update(transaction, "size", B_INT64_TYPE, NULL, 0, (uint8*)&size,
@@ -332,7 +332,7 @@ Index::InsertSize(Transaction &transaction, Inode* inode)
status_t
Index::RemoveSize(Transaction &transaction, Inode* inode)
{
ASSERT(inode->IsFile());
ASSERT(inode->InSizeIndex());
// Inode::OldSize() is the size that's in the index
off_t size = inode->OldSize();
@@ -344,7 +344,7 @@ Index::RemoveSize(Transaction &transaction, Inode* inode)
status_t
Index::UpdateSize(Transaction &transaction, Inode* inode)
{
ASSERT(inode->IsFile());
ASSERT(inode->InSizeIndex());
off_t oldSize = inode->OldSize();
off_t newSize = inode->Size();
@@ -362,7 +362,7 @@ Index::UpdateSize(Transaction &transaction, Inode* inode)
status_t
Index::InsertLastModified(Transaction &transaction, Inode* inode)
{
ASSERT(inode->IsFile() || inode->IsSymLink());
ASSERT(inode->InLastModifiedIndex());
off_t modified = inode->LastModified();
return Update(transaction, "last_modified", B_INT64_TYPE, NULL, 0,
@@ -373,7 +373,7 @@ Index::InsertLastModified(Transaction &transaction, Inode* inode)
status_t
Index::RemoveLastModified(Transaction &transaction, Inode* inode)
{
ASSERT(inode->IsFile() || inode->IsSymLink());
ASSERT(inode->InLastModifiedIndex());
// Inode::OldLastModified() is the value which is in the index
off_t modified = inode->OldLastModified();
@@ -386,7 +386,7 @@ status_t
Index::UpdateLastModified(Transaction &transaction, Inode* inode,
off_t modified)
{
ASSERT(inode->IsFile() || inode->IsSymLink());
ASSERT(inode->InLastModifiedIndex());
off_t oldModified = inode->OldLastModified();
if (modified == -1)
+45 -21
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.
Returns true if there are any blocks to be trimmed.
*/
bool
Inode::NeedsTrimming()
Inode::NeedsTrimming() const
{
// 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.
// Also, if an inode is already in deleted state, we don't bother trimming
// it.
if (IsIndex() || IsDeleted())
if (IsIndex() || IsDeleted()
|| (IsSymLink() && (Flags() & INODE_LONG_SYMLINK) == 0))
return false;
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)
Index index(fVolume);
if (inode->IsRegularNode()) {
if (inode->InNameIndex()) {
index.RemoveName(transaction, name, inode);
// If removing from the index fails, it is not regarded as a
// fatal error and will not be reported back!
// Deleted inodes won't be visible in queries anyway.
}
if (inode->IsFile() || inode->IsSymLink()) {
if (inode->IsFile())
index.RemoveSize(transaction, inode);
if (inode->InSizeIndex())
index.RemoveSize(transaction, inode);
if (inode->InLastModifiedIndex())
index.RemoveLastModified(transaction, inode);
}
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
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
added to the super block.
It will also create the initial B+tree for the inode if it's a directory
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
inode's ID, the inode stays locked - you have to call put_vnode() if you
don't use it anymore.
If the node already exists, this method will fail if O_EXCL is set, or it's
a directory or a symlink. Otherwise, it will just be returned. If O_TRUNC
has been specified, the file will also be truncated.
If the node already exists, this method will fail if \c O_EXCL is set, or
it's a directory or a symlink. Otherwise, it will just be returned.
If \c O_TRUNC has been specified, the file will also be truncated.
*/
status_t
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)
Index index(volume);
if (inode->IsRegularNode() && name != NULL) {
if (inode->InNameIndex() && name != NULL) {
// the name index only contains regular files
// (but not the root node where name == NULL)
status = index.InsertName(transaction, name, inode);
@@ -2514,14 +2515,13 @@ Inode::Create(Transaction& transaction, Inode* parent, const char* name,
inode->UpdateOldLastModified();
// 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
// harmed; they are considered less important than the "name" index
if (inode->IsFile())
index.InsertSize(transaction, inode);
// The "size" & "last_modified" indices don't contain directories.
// If adding to these indices fails, the inode creation will not be
// harmed; they are considered less important than the "name" index.
if (inode->InSizeIndex())
index.InsertSize(transaction, inode);
if (inode->InLastModifiedIndex())
index.InsertLastModified(transaction, inode);
}
if (inode->IsFile() || inode->IsAttribute()) {
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
+6 -1
View File
@@ -140,12 +140,13 @@ public:
status_t SetFileSize(Transaction& transaction, off_t size);
status_t Append(Transaction& transaction, off_t bytes);
status_t TrimPreallocation(Transaction& transaction);
bool NeedsTrimming();
bool NeedsTrimming() const;
status_t Free(Transaction& transaction);
status_t Sync();
bfs_inode& Node() { return fNode; }
const bfs_inode& Node() const { return fNode; }
// create/remove inodes
status_t Remove(Transaction& transaction, const char* name,
@@ -165,6 +166,10 @@ public:
off_t OldSize() { return fOldSize; }
off_t OldLastModified() { return fOldLastModified; }
bool InNameIndex() const;
bool InSizeIndex() const;
bool InLastModifiedIndex() const;
// file cache
void* FileCache() const { return fCache; }
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();
if (mask & B_STAT_SIZE) {
if ((mask & B_STAT_SIZE) != 0) {
// Since WSTAT_SIZE is the only thing that can fail directly, we
// do it first, so that the inode state will still be consistent
// with the on-disk version
if (inode->IsDirectory())
return B_IS_A_DIRECTORY;
if (!inode->IsFile())
return B_BAD_VALUE;
if (inode->Size() != stat->st_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));
node.mode = HOST_ENDIAN_TO_BFS_INT32((node.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);
if (mask & B_STAT_GID)
if ((mask & B_STAT_GID) != 0)
node.gid = HOST_ENDIAN_TO_BFS_INT32(stat->st_gid);
if (mask & B_STAT_MODIFICATION_TIME) {
if (inode->IsDirectory()) {
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);
@@ -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);
}
}
if (mask & B_STAT_CREATION_TIME) {
if ((mask & B_STAT_CREATION_TIME) != 0) {
node.create_time = HOST_ENDIAN_TO_BFS_INT64(
(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()
&& (needsTrimming
|| 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();
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()) {
index.UpdateSize(transaction, inode);
if (inode->InSizeIndex())
index.UpdateSize(transaction, inode);
changedSize = true;
}
if (inode->OldLastModified() != inode->LastModified()) {
index.UpdateLastModified(transaction, inode, inode->LastModified());
if (inode->InLastModifiedIndex()) {
index.UpdateLastModified(transaction, inode,
inode->LastModified());
}
changedTime = true;
// 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())
RETURN_ERROR(B_BAD_VALUE);
if (inode->Flags() & INODE_LONG_SYMLINK) {
if ((inode->Flags() & INODE_LONG_SYMLINK) != 0) {
if (inode->Size() < *_bufferSize)
*_bufferSize = inode->Size();