nfs4: close*() should wake all blocked operations

This commit is contained in:
Pawel Dziepak
2012-06-29 02:15:01 +02:00
parent 19df56ac66
commit be4c74ead3
14 changed files with 279 additions and 69 deletions
@@ -0,0 +1,86 @@
/*
* Copyright 2012 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Paweł Dziepak, [email protected]
*/
#include "Cookie.h"
#include "Inode.h"
#include "Request.h"
vint64 OpenFileCookie::fLastOwnerId = 0;
Cookie::Cookie()
:
fRequests(NULL)
{
mutex_init(&fRequestLock, NULL);
}
Cookie::~Cookie()
{
mutex_destroy(&fRequestLock);
}
status_t
Cookie::RegisterRequest(RPC::Request* req)
{
mutex_lock(&fRequestLock);
RequestEntry* ent = new RequestEntry;
if (ent == NULL) {
mutex_unlock(&fRequestLock);
return B_NO_MEMORY;
}
ent->fRequest = req;
ent->fNext = fRequests;
fRequests = ent;
mutex_unlock(&fRequestLock);
return B_OK;
}
status_t
Cookie::UnregisterRequest(RPC::Request* req)
{
mutex_lock(&fRequestLock);
RequestEntry* ent = fRequests;
RequestEntry* prev = NULL;
while (ent != NULL) {
if (ent->fRequest == req) {
if (prev == NULL)
fRequests = ent->fNext;
else
prev->fNext = ent->fNext;
delete ent;
}
prev = ent;
ent = ent->fNext;
}
mutex_unlock(&fRequestLock);
return B_OK;
}
status_t
Cookie::CancelAll()
{
mutex_lock(&fRequestLock);
RequestEntry* ent = fRequests;
while (ent != NULL) {
fInode->FileSystem()->Server()->WakeCall(ent->fRequest);
ent = ent->fNext;
}
mutex_unlock(&fRequestLock);
return B_OK;
}
@@ -0,0 +1,61 @@
/*
* Copyright 2012 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Paweł Dziepak, [email protected]
*/
#ifndef COOKIE_H
#define COOKIE_H
#include <SupportDefs.h>
#include "Filesystem.h"
class Inode;
struct Cookie {
struct RequestEntry {
RPC::Request* fRequest;
RequestEntry* fNext;
};
Inode* fInode;
RequestEntry* fRequests;
mutex fRequestLock;
Cookie();
virtual ~Cookie();
status_t RegisterRequest(RPC::Request* req);
status_t UnregisterRequest(RPC::Request* req);
status_t CancelAll();
};
struct OpenFileCookie : public Cookie {
uint64 fClientId;
uint32 fMode;
Filehandle fHandle;
uint32 fStateId[3];
uint32 fStateSeq;
uint32 fSequence;
uint64 fOwnerId;
static vint64 fLastOwnerId;
OpenFileCookie* fNext;
OpenFileCookie* fPrev;
};
struct OpenDirCookie : public Cookie {
uint64 fCookie;
uint64 fCookieVerf;
};
#endif // COOKIE_H
+18 -16
View File
@@ -15,9 +15,6 @@
#include "Request.h"
vint64 OpenFileCookie::fLastOwnerId = 0;
Inode::Inode()
{
}
@@ -447,6 +444,7 @@ Inode::Open(int mode, OpenFileCookie* cookie)
bool confirm;
status_t result;
cookie->fInode = this;
cookie->fHandle = fHandle;
cookie->fMode = mode;
cookie->fSequence = 0;
@@ -610,7 +608,7 @@ Inode::Read(OpenFileCookie* cookie, off_t pos, void* buffer, size_t* _length)
req.Read(cookie->fStateId, cookie->fStateSeq, pos + size,
*_length - size);
status_t result = request.Send();
status_t result = request.Send(cookie);
if (result != B_OK)
return result;
@@ -664,7 +662,7 @@ Inode::Read(OpenFileCookie* cookie, off_t pos, void* buffer, size_t* _length)
status_t
Inode::OpenDir(uint64* cookie)
Inode::OpenDir(OpenDirCookie* cookie)
{
if (fType != NF4DIR)
return B_NOT_A_DIRECTORY;
@@ -707,8 +705,9 @@ Inode::OpenDir(uint64* cookie)
if (allowed & ACCESS4_READ != ACCESS4_READ)
return B_PERMISSION_DENIED;
cookie[0] = 0;
cookie[1] = 2;
cookie->fInode = this;
cookie->fCookie = 0;
cookie->fCookieVerf = 2;
return B_OK;
} while (true);
@@ -716,7 +715,7 @@ Inode::OpenDir(uint64* cookie)
status_t
Inode::_ReadDirOnce(DirEntry** dirents, uint32* count, uint64* cookie,
Inode::_ReadDirOnce(DirEntry** dirents, uint32* count, OpenDirCookie* cookie,
bool* eof)
{
do {
@@ -727,9 +726,10 @@ Inode::_ReadDirOnce(DirEntry** dirents, uint32* count, uint64* cookie,
req.PutFH(fHandle);
Attribute attr[] = { FATTR4_FSID, FATTR4_FILEID };
req.ReadDir(*count, cookie, attr, sizeof(attr) / sizeof(Attribute));
req.ReadDir(*count, cookie->fCookie, cookie->fCookieVerf, attr,
sizeof(attr) / sizeof(Attribute));
status_t result = request.Send();
status_t result = request.Send(cookie);
if (result != B_OK)
return result;
@@ -751,7 +751,8 @@ Inode::_ReadDirOnce(DirEntry** dirents, uint32* count, uint64* cookie,
if (result != B_OK)
return result;
return reply.ReadDir(cookie, dirents, count, eof);
return reply.ReadDir(&cookie->fCookie, &cookie->fCookieVerf, dirents,
count, eof);
} while (true);
}
@@ -846,7 +847,8 @@ Inode::_ReadDirUp(struct dirent* de, uint32 pos, uint32 size)
// When directories are cached client should store inode numbers it assigned
// to directroy entries and use them consequently.
status_t
Inode::ReadDir(void* _buffer, uint32 size, uint32* _count, uint64* cookie)
Inode::ReadDir(void* _buffer, uint32 size, uint32* _count,
OpenDirCookie* cookie)
{
uint32 count = 0;
uint32 pos = 0;
@@ -855,17 +857,17 @@ Inode::ReadDir(void* _buffer, uint32 size, uint32* _count, uint64* cookie)
char* buffer = reinterpret_cast<char*>(_buffer);
if (cookie[0] == 0 && cookie[1] == 2 && count < *_count) {
if (cookie->fCookie == 0 && cookie->fCookieVerf == 2 && count < *_count) {
struct dirent* de = reinterpret_cast<dirent*>(buffer + pos);
_FillDirEntry(de, fFileId, ".", pos, size);
pos += de->d_reclen;
count++;
cookie[1]--;
cookie->fCookieVerf--;
}
if (cookie[0] == 0 && cookie[1] == 1 && count < *_count) {
if (cookie->fCookie == 0 && cookie->fCookieVerf == 1 && count < *_count) {
struct dirent* de = reinterpret_cast<dirent*>(buffer + pos);
if (strcmp(fName, "/"))
@@ -875,7 +877,7 @@ Inode::ReadDir(void* _buffer, uint32 size, uint32* _count, uint64* cookie)
pos += de->d_reclen;
count++;
cookie[1]--;
cookie->fCookieVerf--;
}
bool overflow = false;
+12 -21
View File
@@ -13,29 +13,12 @@
#include <SupportDefs.h>
#include "Cookie.h"
#include "Filesystem.h"
#include "NFS4Defs.h"
#include "ReplyInterpreter.h"
struct OpenFileCookie {
uint64 fClientId;
uint32 fMode;
Filehandle fHandle;
uint32 fStateId[3];
uint32 fStateSeq;
uint32 fSequence;
uint64 fOwnerId;
static vint64 fLastOwnerId;
OpenFileCookie* fNext;
OpenFileCookie* fPrev;
};
class Inode {
public:
static status_t CreateInode(Filesystem* fs, const FileInfo& fi,
@@ -45,6 +28,7 @@ public:
inline ino_t ID() const;
inline mode_t Type() const;
inline const char* Name() const;
inline Filesystem* FileSystem() const;
status_t LookUp(const char* name, ino_t* id);
status_t ReadLink(void* buffer, size_t* length);
@@ -56,9 +40,9 @@ public:
status_t Read(OpenFileCookie* cookie, off_t pos,
void* buffer, size_t* length);
status_t OpenDir(uint64* cookie);
status_t OpenDir(OpenDirCookie* cookie);
status_t ReadDir(void* buffer, uint32 size,
uint32* count, uint64* cookie);
uint32* count, OpenDirCookie* cookie);
private:
Inode();
@@ -66,7 +50,7 @@ private:
status_t _LookUpFilehandle();
status_t _ReadDirOnce(DirEntry** dirents, uint32* count,
uint64* cookie, bool* eof);
OpenDirCookie* cookie, bool* eof);
status_t _FillDirEntry(struct dirent* de, ino_t id,
const char* name, uint32 pos, uint32 size);
status_t _ReadDirUp(struct dirent* de, uint32 pos,
@@ -119,5 +103,12 @@ Inode::Name() const
}
inline Filesystem*
Inode::FileSystem() const
{
return fFilesystem;
}
#endif // INODE_H
@@ -3,6 +3,7 @@ SubDir HAIKU_TOP src add-ons kernel file_systems nfs4 ;
UsePrivateHeaders kernel ;
KernelAddon nfs4 :
Cookie.cpp
Connection.cpp
Filesystem.cpp
Inode.cpp
@@ -155,6 +155,7 @@ Server::SendCallAsync(Call* call, Reply** reply, Request** request)
req->fReply = reply;
req->fEvent.Init(&req->fEvent, NULL);
req->fDone = false;
req->fError = B_OK;
req->fNext = NULL;
fRequests.AddRequest(req);
@@ -185,6 +186,22 @@ Server::ResendCallAsync(Call* call, Request* req)
}
status_t
Server::WakeCall(Request* request)
{
Request* req = fRequests.FindRequest(request->fXID);
if (req == NULL)
return B_OK;
request->fError = B_FILE_ERROR;
*request->fReply = NULL;
request->fDone = true;
request->fEvent.NotifyAll();
return B_OK;
}
status_t
Server::Repair()
{
@@ -22,8 +22,10 @@ namespace RPC {
struct Request {
uint32 fXID;
ConditionVariable fEvent;
bool fDone;
Reply** fReply;
status_t fError;
Request* fNext;
};
@@ -62,6 +64,7 @@ public:
inline status_t WaitCall(Request* request,
bigtime_t time = kWaitTime);
inline status_t CancelCall(Request* request);
status_t WakeCall(Request* request);
status_t Repair();
@@ -237,14 +237,14 @@ ReplyInterpreter::Read(void* buffer, uint32* size, bool* eof)
status_t
ReplyInterpreter::ReadDir(uint64* cookie, DirEntry** dirents, uint32* _count,
bool* eof)
ReplyInterpreter::ReadDir(uint64* cookie, uint64* cookieVerf,
DirEntry** dirents, uint32* _count, bool* eof)
{
status_t res = _OperationError(OpReadDir);
if (res != B_OK)
return res;
cookie[1] = fReply->Stream().GetUHyper();
*cookieVerf = fReply->Stream().GetUHyper();
bool isNext;
uint32 count = 0;
@@ -254,7 +254,7 @@ ReplyInterpreter::ReadDir(uint64* cookie, DirEntry** dirents, uint32* _count,
isNext = fReply->Stream().GetBoolean();
while (isNext && count < *_count) {
cookie[0] = fReply->Stream().GetUHyper();
*cookie = fReply->Stream().GetUHyper();
entries[count].fName = fReply->Stream().GetString();
_DecodeAttrs(fReply->Stream(), &entries[count].fAttrs,
@@ -75,8 +75,8 @@ public:
inline status_t PutFH();
inline status_t PutRootFH();
status_t Read(void* buffer, uint32* size, bool* eof);
status_t ReadDir(uint64* cookie, DirEntry** dirents,
uint32* count, bool* eof);
status_t ReadDir(uint64* cookie, uint64* cookieVerf,
DirEntry** dirents, uint32* count, bool* eof);
status_t ReadLink(void* buffer, uint32* size, uint32 maxSize);
inline status_t Renew();
status_t SetClientID(uint64* clientid, uint64* verifier);
@@ -7,15 +7,16 @@
*/
#include "Inode.h"
#include "Request.h"
status_t
Request::Send()
Request::Send(Cookie* cookie)
{
switch (fServer->ID().fProtocol) {
case ProtocolUDP: return _SendUDP();
case ProtocolTCP: return _SendTCP();
case ProtocolUDP: return _SendUDP(cookie);
case ProtocolTCP: return _SendTCP(cookie);
}
return B_BAD_VALUE;
@@ -23,41 +24,61 @@ Request::Send()
status_t
Request::_SendUDP()
Request::_SendUDP(Cookie* cookie)
{
RPC::Reply *rpl;
RPC::Reply *rpl = NULL;
RPC::Request *rpc;
status_t result = fServer->SendCallAsync(fBuilder.Request(), &rpl, &rpc);
if (result != B_OK)
return result;
if (cookie != NULL)
cookie->RegisterRequest(rpc);
result = fServer->WaitCall(rpc);
if (result != B_OK) {
int attempts = 1;
while (result != B_OK && attempts++ < kRetryLimit) {
result = fServer->ResendCallAsync(fBuilder.Request(), rpc);
if (result != B_OK)
if (result != B_OK) {
if (cookie != NULL)
cookie->UnregisterRequest(rpc);
return result;
}
result = fServer->WaitCall(rpc);
}
if (result != B_OK) {
if (cookie != NULL)
cookie->UnregisterRequest(rpc);
fServer->CancelCall(rpc);
delete rpc;
return result;
}
}
return fReply.SetTo(rpl);
if (cookie != NULL)
cookie->UnregisterRequest(rpc);
if (rpc->fError != B_OK) {
delete rpl;
result = rpc->fError;
delete rpc;
return result;
} else {
fReply.SetTo(rpl);
delete rpc;
return B_OK;
}
}
status_t
Request::_SendTCP()
Request::_SendTCP(Cookie* cookie)
{
RPC::Reply *rpl;
RPC::Reply *rpl = NULL;
RPC::Request *rpc;
status_t result;
@@ -71,8 +92,14 @@ Request::_SendTCP()
continue;
}
if (cookie != NULL)
cookie->RegisterRequest(rpc);
result = fServer->WaitCall(rpc);
if (result != B_OK) {
if (cookie != NULL)
cookie->UnregisterRequest(rpc);
fServer->CancelCall(rpc);
delete rpc;
@@ -80,7 +107,19 @@ Request::_SendTCP()
}
} while (result != B_OK && attempts++ < kRetryLimit);
return fReply.SetTo(rpl);
if (cookie != NULL)
cookie->UnregisterRequest(rpc);
if (rpc->fError != B_OK) {
delete rpl;
result = rpc->fError;
delete rpc;
return result;
} else {
fReply.SetTo(rpl);
delete rpc;
return B_OK;
};
}
@@ -14,6 +14,8 @@
#include "RPCServer.h"
class Cookie;
class Request {
public:
inline Request(RPC::Server* serv);
@@ -21,12 +23,12 @@ public:
inline RequestBuilder& Builder();
inline ReplyInterpreter& Reply();
status_t Send();
status_t Send(Cookie* cookie = NULL);
void Reset();
private:
status_t _SendUDP();
status_t _SendTCP();
status_t _SendUDP(Cookie* cookie);
status_t _SendTCP(Cookie* cookie);
RPC::Server* fServer;
@@ -267,8 +267,8 @@ RequestBuilder::Read(const uint32* id, uint32 stateSeq, uint64 pos, uint32 len)
status_t
RequestBuilder::ReadDir(uint32 count, uint64* cookie, Attribute* attrs,
uint32 attrCount)
RequestBuilder::ReadDir(uint32 count, uint64 cookie, uint64 cookieVerf,
Attribute* attrs, uint32 attrCount)
{
(void)count;
@@ -278,8 +278,8 @@ RequestBuilder::ReadDir(uint32 count, uint64* cookie, Attribute* attrs,
return B_NO_MEMORY;
fRequest->Stream().AddUInt(OpReadDir);
fRequest->Stream().AddUHyper(cookie[0]);
fRequest->Stream().AddUHyper(cookie[1]);
fRequest->Stream().AddUHyper(cookie);
fRequest->Stream().AddUHyper(cookieVerf);
// consider predicting this values basing on count or buffer size
fRequest->Stream().AddUInt(0x2000);
@@ -40,8 +40,9 @@ public:
status_t PutRootFH();
status_t Read(const uint32* id, uint32 stateSeq,
uint64 pos, uint32 len);
status_t ReadDir(uint32 count, uint64* cookie,
Attribute* attrs, uint32 attrCount);
status_t ReadDir(uint32 count, uint64 cookie,
uint64 cookieVerf, Attribute* attrs,
uint32 attrCount);
status_t ReadLink();
status_t Renew(uint64 clientId);
status_t SetClientID(const RPC::Server* serv);
@@ -253,9 +253,15 @@ nfs4_open(fs_volume* volume, fs_vnode* vnode, int openMode, void** _cookie)
static status_t
nfs4_close(fs_volume* volume, fs_vnode* vnode, void* cookie)
nfs4_close(fs_volume* volume, fs_vnode* vnode, void* _cookie)
{
return B_OK;
Inode* inode = reinterpret_cast<Inode*>(vnode->private_node);
if (inode->Type() == S_IFDIR || inode->Type() == S_IFLNK)
return B_OK;
Cookie* cookie = reinterpret_cast<Cookie*>(_cookie);
return cookie->CancelAll();
}
@@ -296,7 +302,7 @@ nfs4_read(fs_volume* volume, fs_vnode* vnode, void* _cookie, off_t pos,
static status_t
nfs4_open_dir(fs_volume* volume, fs_vnode* vnode, void** _cookie)
{
uint64* cookie = new(std::nothrow) uint64[2];
OpenDirCookie* cookie = new(std::nothrow) OpenDirCookie;
if (cookie == NULL)
return B_NO_MEMORY;
*_cookie = cookie;
@@ -311,16 +317,17 @@ nfs4_open_dir(fs_volume* volume, fs_vnode* vnode, void** _cookie)
static status_t
nfs4_close_dir(fs_volume* volume, fs_vnode* vnode, void* cookie)
nfs4_close_dir(fs_volume* volume, fs_vnode* vnode, void* _cookie)
{
return B_OK;
Cookie* cookie = reinterpret_cast<Cookie*>(_cookie);
return cookie->CancelAll();
}
static status_t
nfs4_free_dir_cookie(fs_volume* volume, fs_vnode* vnode, void* cookie)
{
delete[] reinterpret_cast<uint64*>(cookie);
delete reinterpret_cast<OpenDirCookie*>(cookie);
return B_OK;
}
@@ -329,7 +336,7 @@ static status_t
nfs4_read_dir(fs_volume* volume, fs_vnode* vnode, void* _cookie,
struct dirent* buffer, size_t bufferSize, uint32* _num)
{
uint64* cookie = reinterpret_cast<uint64*>(_cookie);
OpenDirCookie* cookie = reinterpret_cast<OpenDirCookie*>(_cookie);
Inode* inode = reinterpret_cast<Inode*>(vnode->private_node);
return inode->ReadDir(buffer, bufferSize, _num, cookie);
}