diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index b663991c7a..c45b663c6d 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -210,6 +210,47 @@ Inode::LookUp(const char* name, ino_t* id) } +// May cause problem similar to Rename (described below). When node's is has +// more than one hard link and we delete the name it stores for filehandle +// restoration node will inocorectly become unavailable. +status_t +Inode::Remove(const char* name) +{ + do { + RPC::Server* serv = fFilesystem->Server(); + Request request(serv); + RequestBuilder& req = request.Builder(); + + req.PutFH(fHandle); + req.Remove(name); + + status_t result = request.Send(); + if (result != B_OK) + return result; + + ReplyInterpreter& reply = request.Reply(); + + // filehandle has expired + if (reply.NFS4Error() == NFS4ERR_FHEXPIRED) { + _LookUpFilehandle(); + continue; + } + + // filesystem has been moved + if (reply.NFS4Error() == NFS4ERR_MOVED) { + fFilesystem->Migrate(fHandle, serv); + continue; + } + + result = reply.PutFH(); + if (result != B_OK) + return result; + + return reply.Remove(); + } while (true); +} + + // Rename may cause some problems if filehandles are volatile and local Inode // object exists for renamed node. It's stored filename will become invalid // and, consequnetly, filehandle restoration will fail. Probably, it will diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h b/src/add-ons/kernel/file_systems/nfs4/Inode.h index 0265dde6df..f47182387a 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -32,6 +32,7 @@ public: status_t LookUp(const char* name, ino_t* id); status_t ReadLink(void* buffer, size_t* length); + status_t Remove(const char* name); static status_t Rename(Inode* from, Inode* to, const char* fromName, const char* toName); status_t Access(int mode); diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h index c6c7ce4b74..7db013f6d2 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h @@ -34,6 +34,7 @@ enum Opcode { OpRead = 25, OpReadDir = 26, OpReadLink = 27, + OpRemove = 28, OpRename = 29, OpRenew = 30, OpSaveFH = 32, diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp index 0207d323c1..003e31f585 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp @@ -290,6 +290,21 @@ ReplyInterpreter::ReadLink(void* buffer, uint32* size, uint32 maxSize) } +status_t +ReplyInterpreter::Remove() +{ + status_t res = _OperationError(OpRemove); + if (res != B_OK) + return res; + + fReply->Stream().GetBoolean(); + fReply->Stream().GetUHyper(); + fReply->Stream().GetUHyper(); + + return fReply->Stream().IsEOF() ? B_BAD_VALUE : B_OK; +} + + status_t ReplyInterpreter::Rename() { diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h index a96262973a..ab295dfa7f 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h @@ -78,6 +78,7 @@ public: status_t ReadDir(uint64* cookie, uint64* cookieVerf, DirEntry** dirents, uint32* count, bool* eof); status_t ReadLink(void* buffer, uint32* size, uint32 maxSize); + status_t Remove(); status_t Rename(); inline status_t Renew(); inline status_t SaveFH(); diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp index 628ea3f865..c0901baaae 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp @@ -308,6 +308,23 @@ RequestBuilder::ReadLink() } +status_t +RequestBuilder::Remove(const char* file) +{ + if (fProcedure != ProcCompound) + return B_BAD_VALUE; + if (fRequest == NULL) + return B_NO_MEMORY; + + fRequest->Stream().AddUInt(OpRemove); + fRequest->Stream().AddString(file); + + fOpCount++; + + return B_OK; +} + + status_t RequestBuilder::Rename(const char* from, const char* to) { diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h index 26823c4e39..61c1d19daa 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h @@ -44,6 +44,7 @@ public: uint64 cookieVerf, Attribute* attrs, uint32 attrCount); status_t ReadLink(); + status_t Remove(const char* file); status_t Rename(const char* from, const char* to); status_t Renew(uint64 clientId); status_t SaveFH(); 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 4598d8637a..adf6d19eb9 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -212,6 +212,14 @@ nfs4_read_symlink(fs_volume* volume, fs_vnode* link, char* buffer, } +static status_t +nfs4_unlink(fs_volume* volume, fs_vnode* dir, const char* name) +{ + Inode* inode = reinterpret_cast(dir->private_node); + return inode->Remove(name); +} + + static status_t nfs4_rename(fs_volume* volume, fs_vnode* fromDir, const char* fromName, fs_vnode* toDir, const char* toName) @@ -309,6 +317,14 @@ nfs4_read(fs_volume* volume, fs_vnode* vnode, void* _cookie, off_t pos, } +static status_t +nfs4_remove_dir(fs_volume* volume, fs_vnode* parent, const char* name) +{ + Inode* inode = reinterpret_cast(parent->private_node); + return inode->Remove(name); +} + + static status_t nfs4_open_dir(fs_volume* volume, fs_vnode* vnode, void** _cookie) { @@ -434,7 +450,7 @@ fs_vnode_ops gNFSv4VnodeOps = { NULL, // create_symlink() NULL, // link() - NULL, // unlink() + nfs4_unlink, nfs4_rename, nfs4_access, @@ -452,7 +468,7 @@ fs_vnode_ops gNFSv4VnodeOps = { /* directory operations */ NULL, // create_dir() - NULL, // remove_dir() + nfs4_remove_dir, nfs4_open_dir, nfs4_close_dir, nfs4_free_dir_cookie,