nfs4: Add support for CB_GETATTR

This commit is contained in:
Pawel Dziepak
2012-08-06 23:26:37 +02:00
parent 0dff48c7ea
commit 224d602294
9 changed files with 143 additions and 0 deletions
@@ -34,6 +34,9 @@ public:
inline uint64 MaxFileSize();
inline uint64 Change();
inline bool Dirty();
void SetDelegation(Delegation* delegation);
void RecallDelegation(bool truncate = false);
void RecallReadDelegation();
@@ -195,5 +198,19 @@ Inode::MaxFileSize()
}
inline uint64
Inode::Change()
{
return fChange;
}
inline bool
Inode::Dirty()
{
return fWriteDirty;
}
#endif // INODE_H
@@ -31,6 +31,8 @@ Inode::CreateState(const char* name, int mode, int perms, OpenState* state,
if (result != B_OK)
return result;
RevalidateFileCache();
FileInfo fi;
fi.fFileId = fileID;
fi.fHandle = handle;
@@ -26,6 +26,7 @@ enum CallbackProcedure {
};
enum CallbackOpcode {
OpCallbackGetAttr = 3,
OpCallbackRecall = 4
};
@@ -135,6 +136,10 @@ enum Attribute {
FATTR4_MAXIMUM_ATTR_ID
};
enum CallbackAttr {
CallbackAttrSize = 1,
CallbackAttrChange = 2
};
static inline bool sIsAttrSet(Attribute attr, const uint32* bitmap,
uint32 count)
@@ -284,6 +284,9 @@ NFS4Server::ProcessCallback(RPC::CallbackRequest* request,
for (uint32 i = 0; i < count; i++) {
switch (req.Operation()) {
case OpCallbackGetAttr:
result = CallbackGetAttr(&req, &reply);
break;
case OpCallbackRecall:
result = CallbackRecall(&req, &reply);
break;
@@ -343,6 +346,48 @@ NFS4Server::CallbackRecall(RequestInterpreter* request, ReplyBuilder* reply)
}
status_t
NFS4Server::CallbackGetAttr(RequestInterpreter* request, ReplyBuilder* reply)
{
FileHandle handle;
int mask;
status_t result = request->GetAttr(&handle, &mask);
if (result != B_OK)
return result;
return B_OK;
MutexLocker locker(fFSLock);
Delegation* delegation = NULL;
FileSystem* current = fFileSystems;
while (current != NULL) {
delegation = current->GetDelegation(handle);
if (delegation != NULL)
break;
current = current->fNext;
}
locker.Unlock();
if (delegation == NULL) {
reply->GetAttr(B_FILE_NOT_FOUND, 0, 0, 0);
return B_FILE_NOT_FOUND;
}
struct stat st;
delegation->GetInode()->Stat(&st);
uint64 change;
change = delegation->GetInode()->Change();
if (delegation->GetInode()->Dirty())
change++;
reply->GetAttr(B_OK, mask, st.st_size, change);
return B_OK;
}
status_t
NFS4Server::RecallAll()
{
@@ -43,6 +43,9 @@ public:
status_t CallbackRecall(RequestInterpreter* request,
ReplyBuilder* reply);
status_t RecallAll();
status_t CallbackGetAttr(RequestInterpreter* request,
ReplyBuilder* reply);
private:
status_t _GetLeaseTime();
@@ -56,6 +56,40 @@ ReplyBuilder::Reply()
}
status_t
ReplyBuilder::GetAttr(status_t status, int mask, uint64 size, uint64 change)
{
if (fStatus != B_OK)
return B_ERROR;
fReply->Stream().AddUInt(OpCallbackGetAttr);
fReply->Stream().AddUInt(_HaikuErrorToNFS4(fStatus));
fStatus = status;
if (status == B_OK) {
uint32 bitmap = 0;
if ((mask & CallbackAttrChange) != 0)
bitmap |= 1 << FATTR4_CHANGE;
if ((mask & CallbackAttrSize) != 0)
bitmap |= 1 << FATTR4_SIZE;
fReply->Stream().AddUInt(1);
fReply->Stream().AddUInt(bitmap);
XDR::WriteStream str;
if ((mask & CallbackAttrChange) != 0)
str.AddUHyper(change);
if ((mask & CallbackAttrSize) != 0)
str.AddUHyper(size);
fReply->Stream().AddOpaque(str);
}
fOpCount++;
return B_OK;
}
status_t
ReplyBuilder::Recall(status_t status)
{
@@ -22,6 +22,8 @@ public:
RPC::CallbackReply* Reply();
status_t GetAttr(status_t status, int mask,
uint64 size, uint64 change);
status_t Recall(status_t status);
private:
@@ -28,6 +28,40 @@ RequestInterpreter::~RequestInterpreter()
}
status_t
RequestInterpreter::GetAttr(FileHandle* handle, int* _mask)
{
if (fLastOperation != OpCallbackGetAttr)
return B_BAD_VALUE;
uint32 size;
const void* ptr = fRequest->Stream().GetOpaque(&size);
handle->fSize = size;
memcpy(handle->fData, ptr, size);
uint32 count = fRequest->Stream().GetUInt();
if (count < 1) {
*_mask = 0;
return fRequest->Stream().IsEOF() ? B_BAD_VALUE : B_OK;
}
uint32 bitmap = fRequest->Stream().GetUInt();
uint32 mask = 0;
if ((bitmap & (1 << FATTR4_CHANGE)) != 0)
mask |= CallbackAttrChange;
if ((bitmap & (1 << FATTR4_SIZE)) != 0)
mask |= CallbackAttrSize;
*_mask = mask;
for (uint32 i = 1; i < count; i++)
fRequest->Stream().GetUInt();
return fRequest->Stream().IsEOF() ? B_BAD_VALUE : B_OK;
}
status_t
RequestInterpreter::Recall(FileHandle* handle, bool& truncate, uint32* stateSeq,
uint32* stateID)
@@ -24,6 +24,7 @@ public:
inline uint32 OperationCount();
inline uint32 Operation();
status_t GetAttr(FileHandle* handle, int* mask);
status_t Recall(FileHandle* handle, bool& truncate,
uint32* stateSeq, uint32* stateID);