From efc29cc57a620c89cbb0ac0be6dfaf522282441e Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Fri, 22 Mar 2013 03:06:50 +0100 Subject: [PATCH] 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 --- .../kernel/file_systems/nfs4/Inode.cpp | 45 +++++++++++-------- src/add-ons/kernel/file_systems/nfs4/Inode.h | 3 +- .../kernel/file_systems/nfs4/NFS4Inode.cpp | 9 ++-- .../file_systems/nfs4/kernel_interface.cpp | 20 ++++++++- 4 files changed, 51 insertions(+), 26 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index 0d2eeea290..e62aaffb4d 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -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(), diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h b/src/add-ons/kernel/file_systems/nfs4/Inode.h index 0c5e8449fe..1e6d47bd31 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -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); diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp index 3dfdd61d80..4d86e0e98f 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp @@ -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) diff --git a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp index 57998827fa..74663cf721 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -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(&vti)) == B_OK); + result = get_vnode(volume, id, reinterpret_cast(&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(&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(&vti)); if (result == B_OK) { Inode* child = vti->Get();