nfs4: update vnode objects and cached data when rename overrides a file

* this patch also fixes unnecessary cache invalidation when a file is renamed
   without changing its parent directory
This commit is contained in:
Pawel Dziepak 2013-03-22 03:06:50 +01:00
parent 4c2a56efe8
commit efc29cc57a
4 changed files with 51 additions and 26 deletions

View File

@ -311,7 +311,7 @@ Inode::Remove(const char* name, FileType type, ino_t* id)
status_t
Inode::Rename(Inode* from, Inode* to, const char* fromName, const char* toName,
bool attribute, ino_t* id)
bool attribute, ino_t* id, ino_t* oldID)
{
ASSERT(from != NULL);
ASSERT(fromName != NULL);
@ -341,8 +341,12 @@ Inode::Rename(Inode* from, Inode* to, const char* fromName, const char* toName,
return B_NO_MEMORY;
}
ChangeInfo fromChange, toChange;
uint64 oldFileID = 0;
if (!attribute)
to->NFS4Inode::LookUp(toName, NULL, &oldFileID, NULL);
uint64 fileID;
ChangeInfo fromChange, toChange;
status_t result = NFS4Inode::RenameNode(from, to, fromName, toName,
&fromChange, &toChange, &fileID, attribute);
if (result != B_OK)
@ -350,32 +354,37 @@ Inode::Rename(Inode* from, Inode* to, const char* fromName, const char* toName,
from->fFileSystem->Root()->MakeInfoInvalid();
if (id != NULL)
*id = FileIdToInoT(fileID);
if (oldID != NULL)
*oldID = FileIdToInoT(oldFileID);
DirectoryCache* cache = attribute ? from->fAttrCache : from->fCache;
cache->Lock();
if (cache->Valid()) {
if (fromChange.fAtomic
&& cache->ChangeInfo() == fromChange.fBefore) {
if (fromChange.fAtomic && cache->ChangeInfo() == fromChange.fBefore) {
cache->RemoveEntry(fromName);
if (to == from)
cache->AddEntry(toName, fileID, true);
cache->SetChangeInfo(fromChange.fAfter);
} else if (cache->ChangeInfo() != fromChange.fBefore)
} else
cache->Trash();
}
cache->Unlock();
if (id != NULL)
*id = FileIdToInoT(fileID);
cache = attribute ? to->fAttrCache : to->fCache;
cache->Lock();
if (cache->Valid()) {
if (toChange.fAtomic
&& cache->ChangeInfo() == toChange.fBefore) {
cache->AddEntry(toName, fileID, true);
cache->SetChangeInfo(toChange.fAfter);
} else if (to->fCache->ChangeInfo() != toChange.fBefore)
cache->Trash();
if (to != from) {
cache = attribute ? to->fAttrCache : to->fCache;
cache->Lock();
if (cache->Valid()) {
if (toChange.fAtomic
&& (cache->ChangeInfo() == toChange.fBefore)) {
cache->AddEntry(toName, fileID, true);
cache->SetChangeInfo(toChange.fAfter);
} else
cache->Trash();
}
cache->Unlock();
}
cache->Unlock();
if (attribute) {
notify_attribute_changed(from->fFileSystem->DevId(), from->ID(),

View File

@ -62,7 +62,8 @@ public:
ino_t* id = NULL);
static status_t Rename(Inode* from, Inode* to,
const char* fromName, const char* toName,
bool attribute = false, ino_t* id = NULL);
bool attribute = false, ino_t* id = NULL,
ino_t* oldID = NULL);
status_t Stat(struct stat* st,
OpenAttrCookie* attr = NULL);

View File

@ -119,9 +119,6 @@ NFS4Inode::LookUp(const char* name, uint64* change, uint64* fileID,
FileHandle* handle, bool parent)
{
ASSERT(name != NULL);
ASSERT(change != NULL);
ASSERT(fileID != NULL);
ASSERT(handle != NULL);
do {
RPC::Server* serv = fFileSystem->Server();
@ -143,7 +140,8 @@ NFS4Inode::LookUp(const char* name, uint64* change, uint64* fileID,
else
req.LookUp(name);
req.GetFH();
if (handle != NULL)
req.GetFH();
Attribute attr[] = { FATTR4_FSID, FATTR4_FILEID };
req.GetAttr(attr, sizeof(attr) / sizeof(Attribute));
@ -177,7 +175,8 @@ NFS4Inode::LookUp(const char* name, uint64* change, uint64* fileID,
if (result != B_OK)
return result;
reply.GetFH(handle);
if (handle != NULL)
reply.GetFH(handle);
result = reply.GetAttr(&values, &count);
if (result != B_OK)

View File

@ -604,7 +604,8 @@ nfs4_unlink(fs_volume* volume, fs_vnode* dir, const char* name)
result = acquire_vnode(volume, id);
if (result == B_OK) {
ASSERT(get_vnode(volume, id, reinterpret_cast<void**>(&vti)) == B_OK);
result = get_vnode(volume, id, reinterpret_cast<void**>(&vti));
ASSERT(result == B_OK);
vti->Remove();
put_vnode(volume, id);
remove_vnode(volume, id);
@ -639,12 +640,27 @@ nfs4_rename(fs_volume* volume, fs_vnode* fromDir, const char* fromName,
return B_ENTRY_NOT_FOUND;
ino_t id;
ino_t oldID;
status_t result = Inode::Rename(fromInode, toInode, fromName, toName, false,
&id);
&id, &oldID);
if (result != B_OK)
return result;
VnodeToInode* vti;
if (oldID != 0) {
// we have overriden an inode
result = acquire_vnode(volume, oldID);
if (result == B_OK) {
result = get_vnode(volume, oldID, reinterpret_cast<void**>(&vti));
ASSERT(result == B_OK);
vti->Remove();
put_vnode(volume, oldID);
remove_vnode(volume, oldID);
put_vnode(volume, oldID);
}
}
result = get_vnode(volume, id, reinterpret_cast<void**>(&vti));
if (result == B_OK) {
Inode* child = vti->Get();