nfs4: Move low level NFS4 code to Inode's base class

This commit is contained in:
Pawel Dziepak
2012-08-04 00:00:25 +02:00
parent 13a90e3795
commit 0dbff36172
11 changed files with 1573 additions and 1512 deletions
File diff suppressed because it is too large Load Diff
+20 -40
View File
@@ -9,17 +9,10 @@
#define INODE_H #define INODE_H
#include <sys/stat.h> #include "NFS4Inode.h"
#include <SupportDefs.h>
#include "Cookie.h"
#include "FileSystem.h"
#include "NFS4Defs.h"
#include "ReplyInterpreter.h"
class Inode { class Inode : public NFS4Inode {
public: public:
static status_t CreateInode(FileSystem* fs, const FileInfo& fi, static status_t CreateInode(FileSystem* fs, const FileInfo& fi,
Inode** inode); Inode** inode);
@@ -36,22 +29,23 @@ public:
inline OpenFileCookie* WriteCookie(); inline OpenFileCookie* WriteCookie();
inline void SetWriteCookie(OpenFileCookie* cookie); inline void SetWriteCookie(OpenFileCookie* cookie);
status_t GetChangeInfo(uint64* change); status_t LookUp(const char* name, ino_t* id);
status_t Access(int mode);
status_t Commit(); status_t Commit();
status_t LookUp(const char* name, ino_t* id); status_t CreateObject(const char* name, const char* path,
int mode, FileType type);
status_t CreateLink(const char* name, const char* path, status_t CreateLink(const char* name, const char* path,
int mode); int mode);
status_t ReadLink(void* buffer, size_t* length);
status_t Link(Inode* dir, const char* name); status_t Link(Inode* dir, const char* name);
status_t Remove(const char* name, FileType type); status_t Remove(const char* name, FileType type);
static status_t Rename(Inode* from, Inode* to, static status_t Rename(Inode* from, Inode* to,
const char* fromName, const char* toName); const char* fromName, const char* toName);
status_t Access(int mode);
status_t Stat(struct stat* st); status_t Stat(struct stat* st);
status_t WriteStat(const struct stat* st, uint32 mask); status_t WriteStat(const struct stat* st, uint32 mask);
@@ -77,46 +71,32 @@ public:
const struct flock* lock); const struct flock* lock);
status_t ReleaseAllLocks(OpenFileCookie* cookie); status_t ReleaseAllLocks(OpenFileCookie* cookie);
protected: protected:
Inode(); Inode();
bool _HandleErrors(uint32 nfs4Error, status_t ReadDirUp(struct dirent* de, uint32 pos,
RPC::Server* serv,
OpenFileCookie* cookie = NULL);
status_t _ConfirmOpen(const FileHandle& fh,
OpenFileCookie* cookie);
status_t _ReadDirOnce(DirEntry** dirents, uint32* count,
OpenDirCookie* cookie, bool* eof,
uint64* change, uint64* dirCookie,
uint64* dirCookieVerf);
status_t _FillDirEntry(struct dirent* de, ino_t id,
const char* name, uint32 pos, uint32 size);
status_t _ReadDirUp(struct dirent* de, uint32 pos,
uint32 size); uint32 size);
status_t _GetDirSnapshot(DirectoryCacheSnapshot** status_t FillDirEntry(struct dirent* de, ino_t id,
const char* name, uint32 pos, uint32 size);
status_t GetDirSnapshot(DirectoryCacheSnapshot**
_snapshot, OpenDirCookie* cookie, _snapshot, OpenDirCookie* cookie,
uint64* _change); uint64* _change);
status_t _ChildAdded(const char* name, uint64 fileID, status_t ChildAdded(const char* name, uint64 fileID,
const FileHandle& fileHandle); const FileHandle& fileHandle);
static inline status_t _CheckLockType(short ltype, uint32 mode); status_t UpdateAttrCache(bool force = false);
static inline ino_t _FileIdToInoT(uint64 fileid); static inline status_t CheckLockType(short ltype, uint32 mode);
static inline ino_t FileIdToInoT(uint64 fileid);
uint32 fType;
struct stat fAttrCache; struct stat fAttrCache;
mutex fAttrCacheLock; mutex fAttrCacheLock;
time_t fAttrCacheExpire; time_t fAttrCacheExpire;
static const time_t kAttrCacheExpirationTime = 60; static const time_t kAttrCacheExpirationTime = 60;
status_t _UpdateAttrCache(bool force = false);
uint32 fType;
FileInfo fInfo;
FileSystem* fFileSystem;
DirectoryCache* fCache; DirectoryCache* fCache;
@@ -130,7 +110,7 @@ protected:
inline ino_t inline ino_t
Inode::_FileIdToInoT(uint64 fileid) Inode::FileIdToInoT(uint64 fileid)
{ {
if (sizeof(ino_t) >= sizeof(uint64)) if (sizeof(ino_t) >= sizeof(uint64))
return fileid; return fileid;
@@ -143,7 +123,7 @@ Inode::_FileIdToInoT(uint64 fileid)
inline ino_t inline ino_t
Inode::ID() const Inode::ID() const
{ {
return _FileIdToInoT(fInfo.fFileId); return FileIdToInoT(fInfo.fFileId);
} }
+26 -206
View File
@@ -20,95 +20,7 @@
status_t status_t
Inode::CreateDir(const char* name, int mode) Inode::CreateDir(const char* name, int mode)
{ {
bool badOwner = false; return CreateObject(name, NULL, mode, NF4DIR);
do {
RPC::Server* serv = fFileSystem->Server();
Request request(serv);
RequestBuilder& req = request.Builder();
req.PutFH(fInfo.fHandle);
uint32 i = 0;
AttrValue cattr[3];
cattr[i].fAttribute = FATTR4_MODE;
cattr[i].fFreePointer = false;
cattr[i].fData.fValue32 = mode;
i++;
if (!badOwner && fFileSystem->IsAttrSupported(FATTR4_OWNER)) {
cattr[i].fAttribute = FATTR4_OWNER;
cattr[i].fFreePointer = true;
cattr[i].fData.fPointer = gIdMapper->GetOwner(getuid());
i++;
}
if (!badOwner && fFileSystem->IsAttrSupported(FATTR4_OWNER_GROUP)) {
cattr[i].fAttribute = FATTR4_OWNER_GROUP;
cattr[i].fFreePointer = true;
cattr[i].fData.fPointer = gIdMapper->GetOwnerGroup(getgid());
i++;
}
req.Create(NF4DIR, name, cattr, i);
req.GetFH();
Attribute attr[] = { FATTR4_FILEID };
req.GetAttr(attr, sizeof(attr) / sizeof(Attribute));
status_t result = request.Send();
if (result != B_OK)
return result;
ReplyInterpreter& reply = request.Reply();
if (reply.NFS4Error() == NFS4ERR_BADOWNER) {
badOwner = true;
continue;
}
if (_HandleErrors(reply.NFS4Error(), serv))
continue;
reply.PutFH();
uint64 before, after;
bool atomic;
result = reply.Create(&before, &after, atomic);
if (result != B_OK)
return result;
FileHandle handle;
result = reply.GetFH(&handle);
if (result != B_OK)
return result;
AttrValue* values;
uint32 count;
result = reply.GetAttr(&values, &count);
if (result != B_OK)
return result;
uint32 fileID;
if (count == 0)
fileID = fFileSystem->AllocFileId();
else
fileID = values[0].fData.fValue64;
result = _ChildAdded(name, fileID, handle);
if (result != B_OK)
return B_OK;
if (fCache->Lock() == B_OK) {
if (atomic && fCache->ChangeInfo() == before) {
fCache->AddEntry(name, fileID, true);
fCache->SetChangeInfo(after);
} else if (fCache->ChangeInfo() != before)
fCache->Trash();
fCache->Unlock();
}
return B_OK;
} while (true);
} }
@@ -118,116 +30,22 @@ Inode::OpenDir(OpenDirCookie* cookie)
if (fType != NF4DIR) if (fType != NF4DIR)
return B_NOT_A_DIRECTORY; return B_NOT_A_DIRECTORY;
do { status_t result = Access(R_OK);
RPC::Server* serv = fFileSystem->Server(); if (result != B_OK)
Request request(serv); return result;
RequestBuilder& req = request.Builder();
req.PutFH(fInfo.fHandle); cookie->fFileSystem = fFileSystem;
req.Access(); cookie->fSpecial = 0;
cookie->fSnapshot = NULL;
cookie->fCurrent = NULL;
cookie->fEOF = false;
status_t result = request.Send(); return B_OK;
if (result != B_OK)
return result;
ReplyInterpreter& reply = request.Reply();
if (_HandleErrors(reply.NFS4Error(), serv))
continue;
reply.PutFH();
uint32 allowed;
result = reply.Access(NULL, &allowed);
if (result != B_OK)
return result;
if (allowed & ACCESS4_READ != ACCESS4_READ)
return B_PERMISSION_DENIED;
cookie->fFileSystem = fFileSystem;
cookie->fSpecial = 0;
cookie->fSnapshot = NULL;
cookie->fCurrent = NULL;
cookie->fEOF = false;
fFileSystem->Root()->MakeInfoInvalid();
return B_OK;
} while (true);
} }
status_t status_t
Inode::_ReadDirOnce(DirEntry** dirents, uint32* count, OpenDirCookie* cookie, Inode::FillDirEntry(struct dirent* de, ino_t id, const char* name, uint32 pos,
bool* eof, uint64* change, uint64* dirCookie, uint64* dirCookieVerf)
{
do {
RPC::Server* serv = fFileSystem->Server();
Request request(serv);
RequestBuilder& req = request.Builder();
req.PutFH(fInfo.fHandle);
Attribute dirAttr[] = { FATTR4_CHANGE };
if (*change == 0)
req.GetAttr(dirAttr, sizeof(dirAttr) / sizeof(Attribute));
Attribute attr[] = { FATTR4_FSID, FATTR4_FILEID };
req.ReadDir(*count, *dirCookie, *dirCookieVerf, attr,
sizeof(attr) / sizeof(Attribute));
req.GetAttr(dirAttr, sizeof(dirAttr) / sizeof(Attribute));
status_t result = request.Send(cookie);
if (result != B_OK)
return result;
ReplyInterpreter& reply = request.Reply();
if (_HandleErrors(reply.NFS4Error(), serv))
continue;
reply.PutFH();
AttrValue* before = NULL;
uint32 attrCount;
if (*change == 0) {
result = reply.GetAttr(&before, &attrCount);
if (result != B_OK)
return result;
}
result = reply.ReadDir(dirCookie, dirCookieVerf, dirents,
count, eof);
if (result != B_OK) {
delete[] before;
return result;
}
AttrValue* after;
result = reply.GetAttr(&after, &attrCount);
if (result != B_OK) {
delete[] before;
return result;
}
if (*change == 0 && before[0].fData.fValue64 == after[0].fData.fValue64
|| *change == after[0].fData.fValue64)
*change = after[0].fData.fValue64;
else
return B_ERROR;
delete[] before;
delete[] after;
return B_OK;
} while (true);
}
status_t
Inode::_FillDirEntry(struct dirent* de, ino_t id, const char* name, uint32 pos,
uint32 size) uint32 size)
{ {
uint32 nameSize = strlen(name); uint32 nameSize = strlen(name);
@@ -249,7 +67,7 @@ Inode::_FillDirEntry(struct dirent* de, ino_t id, const char* name, uint32 pos,
status_t status_t
Inode::_ReadDirUp(struct dirent* de, uint32 pos, uint32 size) Inode::ReadDirUp(struct dirent* de, uint32 pos, uint32 size)
{ {
do { do {
RPC::Server* serv = fFileSystem->Server(); RPC::Server* serv = fFileSystem->Server();
@@ -271,7 +89,7 @@ Inode::_ReadDirUp(struct dirent* de, uint32 pos, uint32 size)
ReplyInterpreter& reply = request.Reply(); ReplyInterpreter& reply = request.Reply();
if (_HandleErrors(reply.NFS4Error(), serv)) if (HandleErrors(reply.NFS4Error(), serv))
continue; continue;
reply.PutFH(); reply.PutFH();
@@ -295,13 +113,13 @@ Inode::_ReadDirUp(struct dirent* de, uint32 pos, uint32 size)
} else } else
fileId = fFileSystem->AllocFileId(); fileId = fFileSystem->AllocFileId();
return _FillDirEntry(de, _FileIdToInoT(fileId), "..", pos, size); return FillDirEntry(de, FileIdToInoT(fileId), "..", pos, size);
} while (true); } while (true);
} }
status_t status_t
Inode::_GetDirSnapshot(DirectoryCacheSnapshot** _snapshot, Inode::GetDirSnapshot(DirectoryCacheSnapshot** _snapshot,
OpenDirCookie* cookie, uint64* _change) OpenDirCookie* cookie, uint64* _change)
{ {
DirectoryCacheSnapshot* snapshot = new DirectoryCacheSnapshot; DirectoryCacheSnapshot* snapshot = new DirectoryCacheSnapshot;
@@ -317,7 +135,7 @@ Inode::_GetDirSnapshot(DirectoryCacheSnapshot** _snapshot,
uint32 count; uint32 count;
DirEntry* dirents; DirEntry* dirents;
status_t result = _ReadDirOnce(&dirents, &count, cookie, &eof, &change, status_t result = ReadDirOnce(&dirents, &count, cookie, &eof, &change,
&dirCookie, &dirCookieVerf); &dirCookie, &dirCookieVerf);
if (result != B_OK) { if (result != B_OK) {
delete snapshot; delete snapshot;
@@ -335,9 +153,9 @@ Inode::_GetDirSnapshot(DirectoryCacheSnapshot** _snapshot,
ino_t id; ino_t id;
if (dirents[i].fAttrCount == 2) if (dirents[i].fAttrCount == 2)
id = _FileIdToInoT(dirents[i].fAttrs[1].fData.fValue64); id = FileIdToInoT(dirents[i].fAttrs[1].fData.fValue64);
else else
id = _FileIdToInoT(fFileSystem->AllocFileId()); id = FileIdToInoT(fFileSystem->AllocFileId());
NameCacheEntry* entry = new NameCacheEntry(dirents[i].fName, id); NameCacheEntry* entry = new NameCacheEntry(dirents[i].fName, id);
if (entry == NULL || entry->fName == NULL) { if (entry == NULL || entry->fName == NULL) {
@@ -381,7 +199,7 @@ Inode::ReadDir(void* _buffer, uint32 size, uint32* _count,
cookie->fSnapshot = fCache->GetSnapshot(); cookie->fSnapshot = fCache->GetSnapshot();
if (cookie->fSnapshot == NULL) { if (cookie->fSnapshot == NULL) {
uint64 change; uint64 change;
result = _GetDirSnapshot(&cookie->fSnapshot, cookie, &change); result = GetDirSnapshot(&cookie->fSnapshot, cookie, &change);
if (result != B_OK) { if (result != B_OK) {
fCache->Unlock(); fCache->Unlock();
fFileSystem->Revalidator().Unlock(); fFileSystem->Revalidator().Unlock();
@@ -405,7 +223,7 @@ Inode::ReadDir(void* _buffer, uint32 size, uint32* _count,
struct dirent* de = reinterpret_cast<dirent*>(buffer + pos); struct dirent* de = reinterpret_cast<dirent*>(buffer + pos);
status_t result; status_t result;
result = _FillDirEntry(de, fInfo.fFileId, ".", pos, size); result = FillDirEntry(de, fInfo.fFileId, ".", pos, size);
if (result == B_BUFFER_OVERFLOW) if (result == B_BUFFER_OVERFLOW)
overflow = true; overflow = true;
@@ -422,9 +240,11 @@ Inode::ReadDir(void* _buffer, uint32 size, uint32* _count,
status_t result; status_t result;
if (strcmp(fInfo.fName, "/")) if (strcmp(fInfo.fName, "/"))
result = _ReadDirUp(de, pos, size); result = ReadDirUp(de, pos, size);
else else {
result = _FillDirEntry(de, _FileIdToInoT(fInfo.fFileId), "..", pos, size); result = FillDirEntry(de, FileIdToInoT(fInfo.fFileId), "..", pos,
size);
}
if (result == B_BUFFER_OVERFLOW) if (result == B_BUFFER_OVERFLOW)
overflow = true; overflow = true;
@@ -452,7 +272,7 @@ Inode::ReadDir(void* _buffer, uint32 size, uint32* _count,
break; break;
} }
if (_FillDirEntry(de, cookie->fCurrent->fNode, cookie->fCurrent->fName, if (FillDirEntry(de, cookie->fCurrent->fNode, cookie->fCurrent->fName,
pos, size) == B_BUFFER_OVERFLOW) { pos, size) == B_BUFFER_OVERFLOW) {
overflow = true; overflow = true;
break; break;
@@ -19,182 +19,55 @@
#include "RootInode.h" #include "RootInode.h"
status_t
Inode::_ConfirmOpen(const FileHandle& fh, OpenFileCookie* cookie)
{
do {
RPC::Server* serv = fFileSystem->Server();
Request request(serv);
RequestBuilder& req = request.Builder();
req.PutFH(fh);
req.OpenConfirm(cookie->fSequence++, cookie->fStateId,
cookie->fStateSeq);
status_t result = request.Send();
if (result != B_OK) {
fFileSystem->RemoveOpenFile(cookie);
return result;
}
ReplyInterpreter& reply = request.Reply();
if (_HandleErrors(reply.NFS4Error(), serv))
continue;
reply.PutFH();
result = reply.OpenConfirm(&cookie->fStateSeq);
if (result != B_OK) {
fFileSystem->RemoveOpenFile(cookie);
return result;
}
break;
} while (true);
return B_OK;
}
status_t status_t
Inode::Create(const char* name, int mode, int perms, OpenFileCookie* cookie, Inode::Create(const char* name, int mode, int perms, OpenFileCookie* cookie,
ino_t* id) ino_t* id)
{ {
bool confirm;
status_t result;
cookie->fMode = mode; cookie->fMode = mode;
cookie->fSequence = 0; cookie->fSequence = 0;
cookie->fLocks = NULL; cookie->fLocks = NULL;
bool badOwner = false; uint64 fileID;
FileHandle fh; FileHandle handle;
do { ChangeInfo changeInfo;
cookie->fClientId = fFileSystem->NFSServer()->ClientId(); status_t result = CreateFile(name, mode, perms, cookie, &changeInfo,
&fileID, &handle);
if (result != B_OK)
return result;
RPC::Server* serv = fFileSystem->Server(); *id = FileIdToInoT(fileID);
Request request(serv);
RequestBuilder& req = request.Builder();
cookie->fOwnerId = atomic_add64(&cookie->fLastOwnerId, 1); FileInfo fi;
fi.fFileId = fileID;
fi.fHandle = handle;
fi.fParent = fInfo.fHandle;
fi.fName = strdup(name);
req.PutFH(fInfo.fHandle); char* path = reinterpret_cast<char*>(malloc(strlen(name) + 2 +
strlen(fInfo.fPath)));
strcpy(path, fInfo.fPath);
strcat(path, "/");
strcat(path, name);
fi.fPath = path;
AttrValue cattr[4]; fFileSystem->InoIdMap()->AddEntry(fi, *id);
uint32 i = 0;
if ((mode & O_TRUNC) == O_TRUNC) {
cattr[i].fAttribute = FATTR4_SIZE;
cattr[i].fFreePointer = false;
cattr[i].fData.fValue64 = 0;
i++;
}
cattr[i].fAttribute = FATTR4_MODE;
cattr[i].fFreePointer = false;
cattr[i].fData.fValue32 = perms;
i++;
if (!badOwner && fFileSystem->IsAttrSupported(FATTR4_OWNER)) { if (fCache->Lock() == B_OK) {
cattr[i].fAttribute = FATTR4_OWNER; if (changeInfo.fAtomic
cattr[i].fFreePointer = true; && fCache->ChangeInfo() == changeInfo.fBefore) {
cattr[i].fData.fPointer = gIdMapper->GetOwner(getuid()); fCache->AddEntry(name, fileID, true);
i++; fCache->SetChangeInfo(changeInfo.fAfter);
} } else if (fCache->ChangeInfo() != changeInfo.fBefore)
fCache->Trash();
fCache->Unlock();
}
if (!badOwner && fFileSystem->IsAttrSupported(FATTR4_OWNER_GROUP)) { cookie->fFileSystem = fFileSystem;
cattr[i].fAttribute = FATTR4_OWNER_GROUP; cookie->fInfo = fi;
cattr[i].fFreePointer = true;
cattr[i].fData.fPointer = gIdMapper->GetOwnerGroup(getgid());
i++;
}
req.Open(CLAIM_NULL, cookie->fSequence++, sModeToAccess(mode),
cookie->fClientId, OPEN4_CREATE, cookie->fOwnerId, name, cattr,
i, (mode & O_EXCL) == O_EXCL);
req.GetFH();
if (fFileSystem->IsAttrSupported(FATTR4_FILEID)) {
Attribute attr[] = { FATTR4_FILEID };
req.GetAttr(attr, sizeof(attr) / sizeof(Attribute));
}
result = request.Send();
if (result != B_OK)
return result;
ReplyInterpreter& reply = request.Reply();
if (reply.NFS4Error() == NFS4ERR_BADOWNER) {
badOwner = true;
continue;
}
if (_HandleErrors(reply.NFS4Error(), serv))
continue;
reply.PutFH();
bool atomic;
uint64 before, after;
result = reply.Open(cookie->fStateId, &cookie->fStateSeq, &confirm,
&before, &after, &atomic);
if (result != B_OK)
return result;
reply.GetFH(&fh);
uint64 fileId;
if (fFileSystem->IsAttrSupported(FATTR4_FILEID)) {
AttrValue* values;
uint32 count;
result = reply.GetAttr(&values, &count);
if (result != B_OK)
return result;
fileId = values[0].fData.fValue64;
delete[] values;
} else
fileId = fFileSystem->AllocFileId();
*id = _FileIdToInoT(fileId);
FileInfo fi;
fi.fFileId = fileId;
fi.fHandle = fh;
fi.fParent = fInfo.fHandle;
fi.fName = strdup(name);
char* path = reinterpret_cast<char*>(malloc(strlen(name) + 2 +
strlen(fInfo.fPath)));
strcpy(path, fInfo.fPath);
strcat(path, "/");
strcat(path, name);
fi.fPath = path;
fFileSystem->InoIdMap()->AddEntry(fi, *id);
if (fCache->Lock() == B_OK) {
if (atomic && fCache->ChangeInfo() == before) {
fCache->AddEntry(name, fileId, true);
fCache->SetChangeInfo(after);
} else if (fCache->ChangeInfo() != before)
fCache->Trash();
fCache->Unlock();
}
cookie->fFileSystem = fFileSystem;
cookie->fInfo = fi;
break;
} while (true);
fFileSystem->AddOpenFile(cookie); fFileSystem->AddOpenFile(cookie);
fFileSystem->Root()->MakeInfoInvalid(); fFileSystem->Root()->MakeInfoInvalid();
if (confirm)
return _ConfirmOpen(fh, cookie);
return B_OK; return B_OK;
} }
@@ -202,95 +75,18 @@ Inode::Create(const char* name, int mode, int perms, OpenFileCookie* cookie,
status_t status_t
Inode::Open(int mode, OpenFileCookie* cookie) Inode::Open(int mode, OpenFileCookie* cookie)
{ {
bool confirm;
status_t result;
cookie->fFileSystem = fFileSystem; cookie->fFileSystem = fFileSystem;
cookie->fInfo = fInfo; cookie->fInfo = fInfo;
cookie->fMode = mode; cookie->fMode = mode;
cookie->fSequence = 0; cookie->fSequence = 0;
cookie->fLocks = NULL; cookie->fLocks = NULL;
do { status_t result = OpenFile(cookie, mode);
cookie->fClientId = fFileSystem->NFSServer()->ClientId(); if (result != B_OK)
return result;
RPC::Server* serv = fFileSystem->Server();
Request request(serv);
RequestBuilder& req = request.Builder();
cookie->fOwnerId = atomic_add64(&cookie->fLastOwnerId, 1);
// Since we are opening the file using a pair (parentFH, name) we
// need to check for race conditions.
if (fFileSystem->IsAttrSupported(FATTR4_FILEID)) {
req.PutFH(fInfo.fParent);
req.LookUp(fInfo.fName);
AttrValue attr;
attr.fAttribute = FATTR4_FILEID;
attr.fFreePointer = false;
attr.fData.fValue64 = fInfo.fFileId;
req.Verify(&attr, 1);
} else if (fFileSystem->ExpireType() == FH4_PERSISTENT) {
req.PutFH(fInfo.fParent);
req.LookUp(fInfo.fName);
AttrValue attr;
attr.fAttribute = FATTR4_FILEHANDLE;
attr.fFreePointer = true;
attr.fData.fPointer = malloc(sizeof(fInfo.fHandle));
memcpy(attr.fData.fPointer, &fInfo.fHandle, sizeof(fInfo.fHandle));
req.Verify(&attr, 1);
}
req.PutFH(fInfo.fParent);
if ((mode & O_TRUNC) == O_TRUNC) {
AttrValue attr;
attr.fAttribute = FATTR4_SIZE;
attr.fFreePointer = false;
attr.fData.fValue64 = 0;
req.Open(CLAIM_NULL, cookie->fSequence++, sModeToAccess(mode),
cookie->fClientId, OPEN4_CREATE, cookie->fOwnerId, fInfo.fName,
&attr, 1, false);
} else
req.Open(CLAIM_NULL, cookie->fSequence++, sModeToAccess(mode),
cookie->fClientId, OPEN4_NOCREATE, cookie->fOwnerId, fInfo.fName);
result = request.Send();
if (result != B_OK)
return result;
ReplyInterpreter& reply = request.Reply();
if (_HandleErrors(reply.NFS4Error(), serv))
continue;
// Verify if the file we want to open is the file this Inode
// represents.
if (fFileSystem->IsAttrSupported(FATTR4_FILEID) ||
fFileSystem->ExpireType() == FH4_PERSISTENT) {
reply.PutFH();
result = reply.LookUp();
if (result != B_OK)
return result;
result = reply.Verify();
if (result != B_OK && reply.NFS4Error() == NFS4ERR_NOT_SAME)
return B_ENTRY_NOT_FOUND;
else if (result != B_OK)
return result;
}
reply.PutFH();
result = reply.Open(cookie->fStateId, &cookie->fStateSeq, &confirm);
if (result != B_OK)
return result;
break;
} while (true);
fFileSystem->AddOpenFile(cookie); fFileSystem->AddOpenFile(cookie);
if (confirm)
return _ConfirmOpen(fInfo.fHandle, cookie);
return B_OK; return B_OK;
} }
@@ -299,34 +95,7 @@ status_t
Inode::Close(OpenFileCookie* cookie) Inode::Close(OpenFileCookie* cookie)
{ {
fFileSystem->RemoveOpenFile(cookie); fFileSystem->RemoveOpenFile(cookie);
return CloseFile(cookie);
do {
RPC::Server* serv = fFileSystem->Server();
Request request(serv);
RequestBuilder& req = request.Builder();
req.PutFH(fInfo.fHandle);
req.Close(cookie->fSequence++, cookie->fStateId,
cookie->fStateSeq);
status_t result = request.Send();
if (result != B_OK)
return result;
ReplyInterpreter& reply = request.Reply();
if (_HandleErrors(reply.NFS4Error(), serv, cookie))
continue;
reply.PutFH();
result = reply.Close();
if (result != B_OK)
return result;
break;
} while (true);
return B_OK;
} }
@@ -336,37 +105,20 @@ Inode::Read(OpenFileCookie* cookie, off_t pos, void* buffer, size_t* _length,
{ {
*eof = false; *eof = false;
uint32 size = 0; uint32 size = 0;
uint32 len = 0;
status_t result;
while (size < *_length && !*eof) { while (size < *_length && !*eof) {
do { uint32 len = *_length - size;
RPC::Server* serv = fFileSystem->Server(); result = ReadFile(cookie, pos + size, &len,
Request request(serv); reinterpret_cast<char*>(buffer) + size, eof);
RequestBuilder& req = request.Builder(); if (result != B_OK) {
if (size == 0)
req.PutFH(fInfo.fHandle);
req.Read(cookie->fStateId, cookie->fStateSeq, pos + size,
*_length - size);
status_t result = request.Send(cookie);
if (result != B_OK)
return result; return result;
else
break;
}
ReplyInterpreter& reply = request.Reply(); size += len;
if (_HandleErrors(reply.NFS4Error(), serv, cookie))
continue;
reply.PutFH();
result = reply.Read(reinterpret_cast<char*>(buffer) + size, &len,
eof);
if (result != B_OK)
return result;
size += len;
break;
} while (true);
} }
*_length = size; *_length = size;
@@ -380,74 +132,21 @@ Inode::Write(OpenFileCookie* cookie, off_t pos, const void* _buffer,
size_t *_length) size_t *_length)
{ {
uint32 size = 0; uint32 size = 0;
uint32 len = 0;
uint64 fileSize;
const char* buffer = reinterpret_cast<const char*>(_buffer); const char* buffer = reinterpret_cast<const char*>(_buffer);
fWriteDirty = true; fWriteDirty = true;
while (size < *_length) { while (size < *_length) {
do { uint32 len = *_length - size;
RPC::Server* serv = fFileSystem->Server(); status_t result = WriteFile(cookie, pos + size, &len, buffer + size);
Request request(serv); if (result != B_OK) {
RequestBuilder& req = request.Builder(); if (size == 0)
if (size == 0 && (cookie->fMode & O_APPEND) == O_APPEND) {
struct stat st;
status_t result = Stat(&st);
if (result != B_OK)
return result;
fileSize = st.st_size;
pos = fileSize;
}
req.PutFH(fInfo.fHandle);
if ((cookie->fMode & O_APPEND) == O_APPEND) {
AttrValue attr;
attr.fAttribute = FATTR4_SIZE;
attr.fFreePointer = false;
attr.fData.fValue64 = fileSize + size;
req.Verify(&attr, 1);
}
req.Write(cookie->fStateId, cookie->fStateSeq, buffer + size,
pos + size, *_length - size);
status_t result = request.Send(cookie);
if (result != B_OK)
return result; return result;
else
break;
}
ReplyInterpreter& reply = request.Reply(); size += len;
// append: race condition
if (reply.NFS4Error() == NFS4ERR_NOT_SAME) {
if (size == 0)
continue;
else {
*_length = size;
return B_OK;
}
}
if (_HandleErrors(reply.NFS4Error(), serv, cookie))
continue;
reply.PutFH();
if ((cookie->fMode & O_APPEND) == O_APPEND) {
result = reply.Verify();
if (result != B_OK)
return result;
}
result = reply.Write(&len);
if (result != B_OK)
return result;
size += len;
break;
} while (true);
} }
*_length = size; *_length = size;
@@ -464,26 +163,10 @@ Inode::Commit()
{ {
if (!fWriteDirty) if (!fWriteDirty)
return B_OK; return B_OK;
status_t result = CommitWrites();
do { if (result != B_OK)
RPC::Server* serv = fFileSystem->Server(); return result;
Request request(serv); fWriteDirty = false;
RequestBuilder& req = request.Builder(); return B_OK;
req.PutFH(fInfo.fHandle);
req.Commit(0, 0);
status_t result = request.Send();
if (result != B_OK)
return result;
ReplyInterpreter& reply = request.Reply();
if (_HandleErrors(reply.NFS4Error(), serv))
continue;
reply.PutFH();
return reply.Commit();
} while (true);
} }
@@ -15,6 +15,8 @@ KernelAddon nfs4 :
InodeDir.cpp InodeDir.cpp
InodeRegular.cpp InodeRegular.cpp
kernel_interface.cpp kernel_interface.cpp
NFS4Inode.cpp
NFS4Object.cpp
NFS4Server.cpp NFS4Server.cpp
ReplyInterpreter.cpp ReplyInterpreter.cpp
Request.cpp Request.cpp
@@ -207,6 +207,12 @@ enum OpenFlags {
OPEN4_RESULT_LOCKTYPE_POSIX = 4 OPEN4_RESULT_LOCKTYPE_POSIX = 4
}; };
struct ChangeInfo {
bool fAtomic;
uint64 fBefore;
uint64 fAfter;
};
enum WriteStable { enum WriteStable {
UNSTABLE4 = 0, UNSTABLE4 = 0,
DATA_SYNC4 = 1, DATA_SYNC4 = 1,
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,78 @@
/*
* Copyright 2012 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Paweł Dziepak, [email protected]
*/
#ifndef NFS4INODE_H
#define NFS4INODE_H
#include <sys/stat.h>
#include <SupportDefs.h>
#include "NFS4Object.h"
#include "ReplyInterpreter.h"
class NFS4Inode : protected NFS4Object {
public:
status_t GetChangeInfo(uint64* change);
status_t ReadLink(void* buffer, size_t* length);
protected:
status_t Access(uint32* allowed);
status_t CommitWrites();
status_t LookUp(const char* name, uint64* change, uint64* fileID,
FileHandle* handle);
status_t Link(Inode* dir, const char* name,
ChangeInfo* changeInfo);
static status_t Rename(Inode* from, Inode* to, const char* fromName,
const char* toName, ChangeInfo* fromChange,
ChangeInfo* toChange, uint64* fileID);
status_t GetStat(AttrValue** values, uint32* count);
status_t WriteStat(OpenFileCookie* cookie, AttrValue* attrs,
uint32 attrCount);
status_t CreateFile(const char* name, int mode, int perms,
OpenFileCookie* cookie, ChangeInfo* changeInfo,
uint64* fileID, FileHandle* handle);
status_t OpenFile(OpenFileCookie* cookie, int mode);
status_t CloseFile(OpenFileCookie* cookie);
status_t ReadFile(OpenFileCookie* cookie, uint64 position,
uint32* length, void* buffer, bool* eof);
status_t WriteFile(OpenFileCookie* cookie, uint64 position,
uint32* length, const void* buffer);
status_t CreateObject(const char* name, const char* path,
int mode, FileType type, ChangeInfo* changeInfo,
uint64* fileID, FileHandle* handle);
status_t RemoveObject(const char* name, FileType type,
ChangeInfo* changeInfo);
status_t ReadDirOnce(DirEntry** dirents, uint32* count,
OpenDirCookie* cookie, bool* eof, uint64* change,
uint64* dirCookie, uint64* dirCookieVerf);
status_t TestLock(OpenFileCookie* cookie, LockType* type,
uint64* position, uint64* length, bool& conflict);
status_t AcquireLock(OpenFileCookie* cookie, LockInfo* lockInfo,
bool wait);
status_t ReleaseLock(OpenFileCookie* cookie, LockInfo* lockInfo);
status_t ConfirmOpen(const FileHandle& fileHandle,
OpenFileCookie* cookie);
};
#endif // NFS4INODE_H
@@ -0,0 +1,89 @@
/*
* Copyright 2012 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Paweł Dziepak, [email protected]
*/
#include "NFS4Object.h"
bool
NFS4Object::HandleErrors(uint32 nfs4Error, RPC::Server* serv,
OpenFileCookie* cookie)
{
uint32 leaseTime;
switch (nfs4Error) {
case NFS4_OK:
return false;
// server needs more time, we need to wait
case NFS4ERR_LOCKED:
case NFS4ERR_DELAY:
if (cookie == NULL) {
snooze_etc(sSecToBigTime(5), B_SYSTEM_TIMEBASE,
B_RELATIVE_TIMEOUT);
return true;
} else if ((cookie->fMode & O_NONBLOCK) == 0) {
status_t result = acquire_sem_etc(cookie->fSnoozeCancel, 1,
B_RELATIVE_TIMEOUT, sSecToBigTime(5));
if (result != B_TIMED_OUT) {
release_sem(cookie->fSnoozeCancel);
return false;
}
return true;
}
return false;
// server is in grace period, we need to wait
case NFS4ERR_GRACE:
leaseTime = fFileSystem->NFSServer()->LeaseTime();
if (cookie == NULL) {
snooze_etc(sSecToBigTime(leaseTime) / 3, B_SYSTEM_TIMEBASE,
B_RELATIVE_TIMEOUT);
return true;
} else if ((cookie->fMode & O_NONBLOCK) == 0) {
status_t result = acquire_sem_etc(cookie->fSnoozeCancel, 1,
B_RELATIVE_TIMEOUT, sSecToBigTime(leaseTime) / 3);
if (result != B_TIMED_OUT) {
release_sem(cookie->fSnoozeCancel);
return false;
}
return true;
}
return false;
// server has rebooted, reclaim share and try again
case NFS4ERR_STALE_CLIENTID:
case NFS4ERR_STALE_STATEID:
fFileSystem->NFSServer()->ServerRebooted(cookie->fClientId);
return true;
// FileHandle has expired
case NFS4ERR_FHEXPIRED:
if (fInfo.UpdateFileHandles(fFileSystem) == B_OK)
return true;
return false;
// filesystem has been moved
case NFS4ERR_LEASE_MOVED:
case NFS4ERR_MOVED:
fFileSystem->Migrate(serv);
return true;
// lease has expired
case NFS4ERR_EXPIRED:
if (cookie != NULL) {
fFileSystem->NFSServer()->ClientId(cookie->fClientId, true);
return true;
}
return false;
default:
return false;
}
}
@@ -0,0 +1,29 @@
/*
* Copyright 2012 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Paweł Dziepak, [email protected]
*/
#ifndef NFS4OBJECT_H
#define NFS4OBJECT_H
#include "Cookie.h"
#include "FileSystem.h"
#include "NFS4Defs.h"
class NFS4Object {
public:
bool HandleErrors(uint32 nfs4Error, RPC::Server* serv,
OpenFileCookie* cookie = NULL);
protected:
FileInfo fInfo;
FileSystem* fFileSystem;
};
#endif // NFS4OBJECT_H
@@ -70,7 +70,7 @@ RootInode::_UpdateInfo(bool force)
ReplyInterpreter& reply = request.Reply(); ReplyInterpreter& reply = request.Reply();
if (_HandleErrors(reply.NFS4Error(), serv)) if (HandleErrors(reply.NFS4Error(), serv))
continue; continue;
reply.PutFH(); reply.PutFH();
@@ -152,7 +152,7 @@ RootInode::ProbeMigration()
if (reply.NFS4Error() == NFS4ERR_MOVED) if (reply.NFS4Error() == NFS4ERR_MOVED)
return true; return true;
if (_HandleErrors(reply.NFS4Error(), serv)) if (HandleErrors(reply.NFS4Error(), serv))
continue; continue;
return false; return false;
@@ -179,7 +179,7 @@ RootInode::GetLocations(AttrValue** attrv)
ReplyInterpreter& reply = request.Reply(); ReplyInterpreter& reply = request.Reply();
if (_HandleErrors(reply.NFS4Error(), serv)) if (HandleErrors(reply.NFS4Error(), serv))
continue; continue;
reply.PutFH(); reply.PutFH();