* No longer keep the write lock when accessing the attribute data; instead, we

now make sure no one else touched it in the mean time (in order to retrieve
  consistent data for the index update). This should fix bug #5878.
* Squashed a TODO by locking the inode in the transaction as well.
* Fixed a quasi bug that would not have read the attribute data if there was no
  live query for it; "fortunately", Volume::CheckForLiveQuery() is not
  implemented yet, and always returns true.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@36707 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2010-05-07 08:36:31 +00:00
parent 51576f91e8
commit 709b35256a
+20 -8
View File
@@ -1077,7 +1077,7 @@ Inode::WriteAttribute(Transaction& transaction, const char* name, int32 type,
// might happen. // might happen.
Index index(fVolume); Index index(fVolume);
index.SetTo(name); bool hasIndex = index.SetTo(name) == B_OK;
Inode* attribute = NULL; Inode* attribute = NULL;
status_t status = B_OK; status_t status = B_OK;
@@ -1131,14 +1131,27 @@ Inode::WriteAttribute(Transaction& transaction, const char* name, int32 type,
} }
if (attribute != NULL) { if (attribute != NULL) {
// TODO: we need to lock the inode in the transaction, see WriteAt()! WriteLocker writeLocker(attribute->fLock);
if (rw_lock_write_lock(&attribute->fLock) == B_OK) {
if (hasIndex || fVolume->CheckForLiveQuery(name)) {
// Save the old attribute data (if this fails, oldLength will // Save the old attribute data (if this fails, oldLength will
// reflect it) // reflect it)
if (fVolume->CheckForLiveQuery(name) && attribute->Size() > 0) { while (attribute->Size() > 0) {
bigtime_t oldModified = attribute->LastModified();
writeLocker.Unlock();
oldLength = BPLUSTREE_MAX_KEY_LENGTH; oldLength = BPLUSTREE_MAX_KEY_LENGTH;
if (attribute->ReadAt(0, oldBuffer, &oldLength) == B_OK) if (attribute->ReadAt(0, oldBuffer, &oldLength) == B_OK)
oldData = oldBuffer; oldData = oldBuffer;
writeLocker.Lock();
// Read until the data hasn't changed in between
if (oldModified == attribute->LastModified())
break;
oldLength = 0;
}
} }
// check if the data fits into the small_data section again // check if the data fits into the small_data section again
@@ -1148,14 +1161,14 @@ Inode::WriteAttribute(Transaction& transaction, const char* name, int32 type,
if (status == B_OK) { if (status == B_OK) {
// it does - remove its file // it does - remove its file
rw_lock_write_unlock(&attribute->fLock); writeLocker.Unlock();
status = _RemoveAttribute(transaction, name, false, NULL); status = _RemoveAttribute(transaction, name, false, NULL);
} else { } else {
// The attribute type might have been changed - we need to // The attribute type might have been changed - we need to
// adopt the new one // adopt the new one
attribute->Node().type = HOST_ENDIAN_TO_BFS_INT32(type); attribute->Node().type = HOST_ENDIAN_TO_BFS_INT32(type);
status = attribute->WriteBack(transaction); status = attribute->WriteBack(transaction);
rw_lock_write_unlock(&attribute->fLock); writeLocker.Unlock();
if (status == B_OK) { if (status == B_OK) {
status = attribute->WriteAt(transaction, pos, buffer, status = attribute->WriteAt(transaction, pos, buffer,
@@ -1170,9 +1183,8 @@ Inode::WriteAttribute(Transaction& transaction, const char* name, int32 type,
status = WriteBack(transaction); status = WriteBack(transaction);
} }
} else
status = B_ERROR;
attribute->WriteLockInTransaction(transaction);
ReleaseAttribute(attribute); ReleaseAttribute(attribute);
} }