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
|
||||
Inode::OpenDir(OpenDirCookie* cookie)
|
||||
{
|
||||
|
||||
@@ -49,6 +49,8 @@ public:
|
||||
status_t Close(OpenFileCookie* cookie);
|
||||
status_t Read(OpenFileCookie* cookie, off_t pos,
|
||||
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 ReadDir(void* buffer, uint32 size,
|
||||
|
||||
@@ -42,7 +42,8 @@ enum Opcode {
|
||||
OpSaveFH = 32,
|
||||
OpSetClientID = 35,
|
||||
OpSetClientIDConfirm = 36,
|
||||
OpVerify = 37
|
||||
OpVerify = 37,
|
||||
OpWrite = 38
|
||||
};
|
||||
|
||||
enum Access {
|
||||
@@ -171,6 +172,12 @@ enum OpenFlags {
|
||||
OPEN4_RESULT_LOCKTYPE_POSIX = 4
|
||||
};
|
||||
|
||||
enum WriteStable {
|
||||
UNSTABLE4 = 0,
|
||||
DATA_SYNC4 = 1,
|
||||
FILE_SYNC4 = 2
|
||||
};
|
||||
|
||||
enum Errors {
|
||||
NFS4_OK = 0,
|
||||
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*
|
||||
sFlattenPathname(XDR::ReadStream& str)
|
||||
{
|
||||
|
||||
@@ -87,6 +87,7 @@ public:
|
||||
status_t SetClientID(uint64* clientid, uint64* verifier);
|
||||
inline status_t SetClientIDConfirm();
|
||||
inline status_t Verify();
|
||||
status_t Write(uint32* size);
|
||||
|
||||
private:
|
||||
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*
|
||||
RequestBuilder::Request()
|
||||
{
|
||||
|
||||
@@ -58,6 +58,9 @@ public:
|
||||
status_t SetClientID(const RPC::Server* serv);
|
||||
status_t SetClientIDConfirm(uint64 id, uint64 ver);
|
||||
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();
|
||||
|
||||
|
||||
@@ -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
|
||||
nfs4_remove_dir(fs_volume* volume, fs_vnode* parent, const char* name)
|
||||
{
|
||||
@@ -500,7 +518,7 @@ fs_vnode_ops gNFSv4VnodeOps = {
|
||||
nfs4_close,
|
||||
nfs4_free_cookie,
|
||||
nfs4_read,
|
||||
NULL, // write,
|
||||
nfs4_write,
|
||||
|
||||
/* directory operations */
|
||||
NULL, // create_dir()
|
||||
|
||||
Reference in New Issue
Block a user