nfs4: Add write() hook
This commit is contained in:
@@ -1019,6 +1019,74 @@ Inode::Read(OpenFileCookie* cookie, off_t pos, void* buffer, size_t* _length)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
Inode::Write(OpenFileCookie* cookie, off_t pos, const void* _buffer,
|
||||||
|
size_t length)
|
||||||
|
{
|
||||||
|
uint32 size = 0;
|
||||||
|
uint32 len = 0;
|
||||||
|
const char* buffer = reinterpret_cast<const char*>(_buffer);
|
||||||
|
|
||||||
|
while (size < length) {
|
||||||
|
do {
|
||||||
|
RPC::Server* serv = fFilesystem->Server();
|
||||||
|
Request request(serv);
|
||||||
|
RequestBuilder& req = request.Builder();
|
||||||
|
|
||||||
|
req.PutFH(fHandle);
|
||||||
|
req.Write(cookie->fStateId, cookie->fStateSeq, buffer + size,
|
||||||
|
pos + size, length - size);
|
||||||
|
|
||||||
|
status_t result = request.Send(cookie);
|
||||||
|
if (result != B_OK)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
ReplyInterpreter& reply = request.Reply();
|
||||||
|
|
||||||
|
// filehandle has expired
|
||||||
|
if (reply.NFS4Error() == NFS4ERR_FHEXPIRED) {
|
||||||
|
_LookUpFilehandle();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// filesystem has been moved
|
||||||
|
if (reply.NFS4Error() == NFS4ERR_MOVED) {
|
||||||
|
fFilesystem->Migrate(fHandle, serv);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// server is in grace period, we need to wait
|
||||||
|
if (reply.NFS4Error() == NFS4ERR_GRACE) {
|
||||||
|
snooze_etc(fFilesystem->NFSServer()->LeaseTime() / 3,
|
||||||
|
B_SYSTEM_TIMEBASE, B_RELATIVE_TIMEOUT);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// server has rebooted, reclaim share and try again
|
||||||
|
if (reply.NFS4Error() == NFS4ERR_STALE_CLIENTID ||
|
||||||
|
reply.NFS4Error() == NFS4ERR_STALE_STATEID) {
|
||||||
|
fFilesystem->NFSServer()->ServerRebooted(cookie->fClientId);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = reply.PutFH();
|
||||||
|
if (result != B_OK)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
result = reply.Write(&len);
|
||||||
|
if (result != B_OK)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
size += len;
|
||||||
|
|
||||||
|
break;
|
||||||
|
} while (true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
Inode::OpenDir(OpenDirCookie* cookie)
|
Inode::OpenDir(OpenDirCookie* cookie)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -49,6 +49,8 @@ public:
|
|||||||
status_t Close(OpenFileCookie* cookie);
|
status_t Close(OpenFileCookie* cookie);
|
||||||
status_t Read(OpenFileCookie* cookie, off_t pos,
|
status_t Read(OpenFileCookie* cookie, off_t pos,
|
||||||
void* buffer, size_t* length);
|
void* buffer, size_t* length);
|
||||||
|
status_t Write(OpenFileCookie* cookie, off_t pos,
|
||||||
|
const void* buffer, size_t length);
|
||||||
|
|
||||||
status_t OpenDir(OpenDirCookie* cookie);
|
status_t OpenDir(OpenDirCookie* cookie);
|
||||||
status_t ReadDir(void* buffer, uint32 size,
|
status_t ReadDir(void* buffer, uint32 size,
|
||||||
|
|||||||
@@ -42,7 +42,8 @@ enum Opcode {
|
|||||||
OpSaveFH = 32,
|
OpSaveFH = 32,
|
||||||
OpSetClientID = 35,
|
OpSetClientID = 35,
|
||||||
OpSetClientIDConfirm = 36,
|
OpSetClientIDConfirm = 36,
|
||||||
OpVerify = 37
|
OpVerify = 37,
|
||||||
|
OpWrite = 38
|
||||||
};
|
};
|
||||||
|
|
||||||
enum Access {
|
enum Access {
|
||||||
@@ -171,6 +172,12 @@ enum OpenFlags {
|
|||||||
OPEN4_RESULT_LOCKTYPE_POSIX = 4
|
OPEN4_RESULT_LOCKTYPE_POSIX = 4
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum WriteStable {
|
||||||
|
UNSTABLE4 = 0,
|
||||||
|
DATA_SYNC4 = 1,
|
||||||
|
FILE_SYNC4 = 2
|
||||||
|
};
|
||||||
|
|
||||||
enum Errors {
|
enum Errors {
|
||||||
NFS4_OK = 0,
|
NFS4_OK = 0,
|
||||||
NFS4ERR_PERM = 1,
|
NFS4ERR_PERM = 1,
|
||||||
|
|||||||
@@ -372,6 +372,21 @@ ReplyInterpreter::SetClientID(uint64* clientid, uint64* verifier)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
ReplyInterpreter::Write(uint32* size)
|
||||||
|
{
|
||||||
|
status_t res = _OperationError(OpWrite);
|
||||||
|
if (res != B_OK)
|
||||||
|
return res;
|
||||||
|
|
||||||
|
*size = fReply->Stream().GetUInt();
|
||||||
|
fReply->Stream().GetInt();
|
||||||
|
fReply->Stream().GetUHyper();
|
||||||
|
|
||||||
|
return fReply->Stream().IsEOF() ? B_BAD_VALUE : B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static const char*
|
static const char*
|
||||||
sFlattenPathname(XDR::ReadStream& str)
|
sFlattenPathname(XDR::ReadStream& str)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -87,6 +87,7 @@ public:
|
|||||||
status_t SetClientID(uint64* clientid, uint64* verifier);
|
status_t SetClientID(uint64* clientid, uint64* verifier);
|
||||||
inline status_t SetClientIDConfirm();
|
inline status_t SetClientIDConfirm();
|
||||||
inline status_t Verify();
|
inline status_t Verify();
|
||||||
|
status_t Write(uint32* size);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void _ParseHeader();
|
void _ParseHeader();
|
||||||
|
|||||||
@@ -500,6 +500,30 @@ RequestBuilder::Verify(AttrValue* attr, uint32 count)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
RequestBuilder::Write(const uint32* id, uint32 stateSeq, const void* buffer,
|
||||||
|
uint64 pos, uint32 len)
|
||||||
|
{
|
||||||
|
if (fProcedure != ProcCompound)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
if (fRequest == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
fRequest->Stream().AddUInt(OpWrite);
|
||||||
|
fRequest->Stream().AddUInt(stateSeq);
|
||||||
|
fRequest->Stream().AddUInt(id[0]);
|
||||||
|
fRequest->Stream().AddUInt(id[1]);
|
||||||
|
fRequest->Stream().AddUInt(id[2]);
|
||||||
|
fRequest->Stream().AddUHyper(pos);
|
||||||
|
fRequest->Stream().AddInt(FILE_SYNC4);
|
||||||
|
fRequest->Stream().AddOpaque(buffer, len);
|
||||||
|
|
||||||
|
fOpCount++;
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
RPC::Call*
|
RPC::Call*
|
||||||
RequestBuilder::Request()
|
RequestBuilder::Request()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -58,6 +58,9 @@ public:
|
|||||||
status_t SetClientID(const RPC::Server* serv);
|
status_t SetClientID(const RPC::Server* serv);
|
||||||
status_t SetClientIDConfirm(uint64 id, uint64 ver);
|
status_t SetClientIDConfirm(uint64 id, uint64 ver);
|
||||||
status_t Verify(AttrValue* attr, uint32 count);
|
status_t Verify(AttrValue* attr, uint32 count);
|
||||||
|
status_t Write(const uint32* id, uint32 stateSeq,
|
||||||
|
const void* buffer, uint64 pos,
|
||||||
|
uint32 len);
|
||||||
|
|
||||||
RPC::Call* Request();
|
RPC::Call* Request();
|
||||||
|
|
||||||
|
|||||||
@@ -353,6 +353,24 @@ nfs4_read(fs_volume* volume, fs_vnode* vnode, void* _cookie, off_t pos,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
nfs4_write(fs_volume* volume, fs_vnode* vnode, void* _cookie, off_t pos,
|
||||||
|
const void* buffer, size_t* length)
|
||||||
|
{
|
||||||
|
Inode* inode = reinterpret_cast<Inode*>(vnode->private_node);
|
||||||
|
|
||||||
|
if (inode->Type() == S_IFDIR)
|
||||||
|
return B_IS_A_DIRECTORY;
|
||||||
|
|
||||||
|
if (inode->Type() == S_IFLNK)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
OpenFileCookie* cookie = reinterpret_cast<OpenFileCookie*>(_cookie);
|
||||||
|
|
||||||
|
return inode->Write(cookie, pos, buffer, *length);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
nfs4_remove_dir(fs_volume* volume, fs_vnode* parent, const char* name)
|
nfs4_remove_dir(fs_volume* volume, fs_vnode* parent, const char* name)
|
||||||
{
|
{
|
||||||
@@ -500,7 +518,7 @@ fs_vnode_ops gNFSv4VnodeOps = {
|
|||||||
nfs4_close,
|
nfs4_close,
|
||||||
nfs4_free_cookie,
|
nfs4_free_cookie,
|
||||||
nfs4_read,
|
nfs4_read,
|
||||||
NULL, // write,
|
nfs4_write,
|
||||||
|
|
||||||
/* directory operations */
|
/* directory operations */
|
||||||
NULL, // create_dir()
|
NULL, // create_dir()
|
||||||
|
|||||||
Reference in New Issue
Block a user