nfs4: Move low level NFS4 code to Inode's base class
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
Reference in New Issue
Block a user