nfs4: Add create() hook
This commit is contained in:
@@ -654,6 +654,175 @@ Inode::Stat(struct stat* st)
|
||||
}
|
||||
|
||||
|
||||
static OpenAccess
|
||||
sModeToAccess(int mode)
|
||||
{
|
||||
switch (mode & O_RWMASK) {
|
||||
case O_RDONLY:
|
||||
return OPEN4_SHARE_ACCESS_READ;
|
||||
case O_WRONLY:
|
||||
return OPEN4_SHARE_ACCESS_WRITE;
|
||||
case O_RDWR:
|
||||
return OPEN4_SHARE_ACCESS_BOTH;
|
||||
}
|
||||
|
||||
return OPEN4_SHARE_ACCESS_READ;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
sConfirmOpen(Filesystem* fs, Filehandle& fh, OpenFileCookie* cookie)
|
||||
{
|
||||
Request request(fs->Server());
|
||||
|
||||
RequestBuilder& req = request.Builder();
|
||||
|
||||
req.PutFH(fh);
|
||||
req.OpenConfirm(cookie->fSequence++, cookie->fStateId,
|
||||
cookie->fStateSeq);
|
||||
|
||||
status_t result = request.Send();
|
||||
if (result != B_OK) {
|
||||
fs->NFSServer()->RemoveOpenFile(cookie);
|
||||
return result;
|
||||
}
|
||||
|
||||
ReplyInterpreter& reply = request.Reply();
|
||||
|
||||
result = reply.PutFH();
|
||||
if (result != B_OK) {
|
||||
fs->NFSServer()->RemoveOpenFile(cookie);
|
||||
return result;
|
||||
}
|
||||
|
||||
result = reply.OpenConfirm(&cookie->fStateSeq);
|
||||
if (result != B_OK) {
|
||||
fs->NFSServer()->RemoveOpenFile(cookie);
|
||||
return result;
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Inode::Create(const char* name, int mode, int perms, OpenFileCookie* cookie,
|
||||
ino_t* id)
|
||||
{
|
||||
bool confirm;
|
||||
status_t result;
|
||||
|
||||
cookie->fInode = this;
|
||||
cookie->fHandle = fHandle;
|
||||
cookie->fMode = mode;
|
||||
cookie->fSequence = 0;
|
||||
|
||||
Filehandle fh;
|
||||
do {
|
||||
cookie->fClientId = fFilesystem->NFSServer()->ClientId();
|
||||
|
||||
RPC::Server* serv = fFilesystem->Server();
|
||||
Request request(serv);
|
||||
RequestBuilder& req = request.Builder();
|
||||
|
||||
cookie->fOwnerId = atomic_add64(&cookie->fLastOwnerId, 1);
|
||||
|
||||
req.PutFH(fParentFH);
|
||||
|
||||
AttrValue cattr;
|
||||
cattr.fAttribute = FATTR4_MODE;
|
||||
cattr.fFreePointer = false;
|
||||
cattr.fData.fValue32 = perms;
|
||||
req.Open(CLAIM_NULL, cookie->fSequence++, sModeToAccess(mode),
|
||||
cookie->fClientId, OPEN4_CREATE, cookie->fOwnerId, name, &cattr,
|
||||
1, mode & O_EXCL == O_EXCL);
|
||||
|
||||
req.GetFH();
|
||||
|
||||
Attribute attr[] = { FATTR4_FILEID };
|
||||
req.GetAttr(attr, sizeof(attr) / sizeof(Attribute));
|
||||
|
||||
result = request.Send();
|
||||
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) {
|
||||
fFilesystem->NFSServer()->ReleaseCID(cookie->fClientId);
|
||||
snooze_etc(fFilesystem->NFSServer()->LeaseTime() / 3,
|
||||
B_SYSTEM_TIMEBASE, B_RELATIVE_TIMEOUT);
|
||||
continue;
|
||||
}
|
||||
|
||||
result = reply.PutFH();
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
result = reply.Open(cookie->fStateId, &cookie->fStateSeq, &confirm);
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
result = reply.GetFH(&fh);
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
AttrValue* values;
|
||||
uint32 count;
|
||||
result = reply.GetAttr(&values, &count);
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
uint64 fileId;
|
||||
if (count == 1 && values[1].fAttribute == FATTR4_FILEID)
|
||||
fileId = values[1].fData.fValue64;
|
||||
else
|
||||
fileId = fFilesystem->AllocFileId();
|
||||
|
||||
delete[] values;
|
||||
|
||||
*id = _FileIdToInoT(fileId);
|
||||
|
||||
FileInfo fi;
|
||||
fi.fFileId = fileId;
|
||||
fi.fFH = fh;
|
||||
fi.fParent = fHandle;
|
||||
fi.fName = strdup(name);
|
||||
|
||||
char* path = reinterpret_cast<char*>(malloc(strlen(name) + 2 +
|
||||
strlen(fPath)));
|
||||
strcpy(path, fPath);
|
||||
strcat(path, "/");
|
||||
strcat(path, name);
|
||||
fi.fPath = path;
|
||||
|
||||
fFilesystem->InoIdMap()->AddEntry(fi, *id);
|
||||
|
||||
break;
|
||||
} while (true);
|
||||
|
||||
fFilesystem->NFSServer()->AddOpenFile(cookie);
|
||||
|
||||
if (confirm)
|
||||
return sConfirmOpen(fFilesystem, fh, cookie);
|
||||
else
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Inode::Open(int mode, OpenFileCookie* cookie)
|
||||
{
|
||||
@@ -675,7 +844,7 @@ Inode::Open(int mode, OpenFileCookie* cookie)
|
||||
cookie->fOwnerId = atomic_add64(&cookie->fLastOwnerId, 1);
|
||||
|
||||
req.PutFH(fParentFH);
|
||||
req.Open(CLAIM_NULL, cookie->fSequence++, OPEN4_SHARE_ACCESS_READ,
|
||||
req.Open(CLAIM_NULL, cookie->fSequence++, sModeToAccess(mode),
|
||||
cookie->fClientId, OPEN4_NOCREATE, cookie->fOwnerId, fName);
|
||||
|
||||
result = request.Send();
|
||||
@@ -717,37 +886,10 @@ Inode::Open(int mode, OpenFileCookie* cookie)
|
||||
|
||||
fFilesystem->NFSServer()->AddOpenFile(cookie);
|
||||
|
||||
if (confirm) {
|
||||
Request request(fFilesystem->Server());
|
||||
|
||||
RequestBuilder& req = request.Builder();
|
||||
|
||||
req.PutFH(fHandle);
|
||||
req.OpenConfirm(cookie->fSequence++, cookie->fStateId,
|
||||
cookie->fStateSeq);
|
||||
|
||||
result = request.Send();
|
||||
if (result != B_OK) {
|
||||
fFilesystem->NFSServer()->RemoveOpenFile(cookie);
|
||||
return result;
|
||||
}
|
||||
|
||||
ReplyInterpreter& reply = request.Reply();
|
||||
|
||||
result = reply.PutFH();
|
||||
if (result != B_OK) {
|
||||
fFilesystem->NFSServer()->RemoveOpenFile(cookie);
|
||||
return result;
|
||||
}
|
||||
|
||||
result = reply.OpenConfirm(&cookie->fStateSeq);
|
||||
if (result != B_OK) {
|
||||
fFilesystem->NFSServer()->RemoveOpenFile(cookie);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
if (confirm)
|
||||
return sConfirmOpen(fFilesystem, fHandle, cookie);
|
||||
else
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -43,6 +43,8 @@ public:
|
||||
status_t Access(int mode);
|
||||
status_t Stat(struct stat* st);
|
||||
|
||||
status_t Create(const char* name, int mode, int perms,
|
||||
OpenFileCookie* cookie, ino_t* id);
|
||||
status_t Open(int mode, OpenFileCookie* cookie);
|
||||
status_t Close(OpenFileCookie* cookie);
|
||||
status_t Read(OpenFileCookie* cookie, off_t pos,
|
||||
|
||||
@@ -144,7 +144,8 @@ enum FileHandleExpiryType {
|
||||
|
||||
enum OpenAccess {
|
||||
OPEN4_SHARE_ACCESS_READ = 1,
|
||||
OPEN4_SHARE_ACCESS_WRITE = 2
|
||||
OPEN4_SHARE_ACCESS_WRITE = 2,
|
||||
OPEN4_SHARE_ACCESS_BOTH = 3
|
||||
};
|
||||
|
||||
enum OpenCreate {
|
||||
@@ -152,6 +153,12 @@ enum OpenCreate {
|
||||
OPEN4_CREATE = 1
|
||||
};
|
||||
|
||||
enum OpenCreateHow {
|
||||
UNCHECKED4 = 0,
|
||||
GUARDED4 = 1,
|
||||
EXCLUSIVE4 = 2
|
||||
};
|
||||
|
||||
enum OpenClaim {
|
||||
CLAIM_NULL = 0,
|
||||
CLAIM_PREVIOUS = 1,
|
||||
|
||||
@@ -198,7 +198,8 @@ RequestBuilder::LookUpUp()
|
||||
|
||||
status_t
|
||||
RequestBuilder::Open(OpenClaim claim, uint32 seq, uint32 access, uint64 id,
|
||||
OpenCreate oc, uint64 ownerId, const char* name)
|
||||
OpenCreate oc, uint64 ownerId, const char* name, AttrValue* attr,
|
||||
uint32 count, bool excl)
|
||||
{
|
||||
if (fProcedure != ProcCompound)
|
||||
return B_BAD_VALUE;
|
||||
@@ -219,6 +220,11 @@ RequestBuilder::Open(OpenClaim claim, uint32 seq, uint32 access, uint64 id,
|
||||
fRequest->Stream().AddOpaque(owner, pos);
|
||||
|
||||
fRequest->Stream().AddUInt(oc);
|
||||
if (oc == OPEN4_CREATE) {
|
||||
fRequest->Stream().AddInt(excl ? GUARDED4 : UNCHECKED4);
|
||||
_EncodeAttrs(fRequest->Stream(), attr, count);
|
||||
}
|
||||
|
||||
fRequest->Stream().AddUInt(claim);
|
||||
switch (claim) {
|
||||
case CLAIM_NULL:
|
||||
|
||||
@@ -38,7 +38,9 @@ public:
|
||||
status_t LookUpUp();
|
||||
status_t Open(OpenClaim claim, uint32 seq,
|
||||
uint32 access, uint64 id, OpenCreate oc,
|
||||
uint64 ownerId, const char* name);
|
||||
uint64 ownerId, const char* name,
|
||||
AttrValue* attr = NULL,
|
||||
uint32 count = 0, bool excl = false);
|
||||
status_t OpenConfirm(uint32 seq, const uint32* id,
|
||||
uint32 stateSeq);
|
||||
status_t PutFH(const Filehandle& fh);
|
||||
|
||||
@@ -264,6 +264,24 @@ nfs4_read_stat(fs_volume* volume, fs_vnode* vnode, struct stat* stat)
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
nfs4_create(fs_volume* volume, fs_vnode* dir, const char* name, int openMode,
|
||||
int perms, void** _cookie, ino_t* _newVnodeID)
|
||||
{
|
||||
OpenFileCookie* cookie = new OpenFileCookie;
|
||||
if (cookie == NULL)
|
||||
return B_NO_MEMORY;
|
||||
*_cookie = cookie;
|
||||
|
||||
Inode* inode = reinterpret_cast<Inode*>(dir->private_node);
|
||||
status_t result = inode->Create(name, openMode, perms, cookie, _newVnodeID);
|
||||
if (result != B_OK)
|
||||
delete cookie;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
nfs4_open(fs_volume* volume, fs_vnode* vnode, int openMode, void** _cookie)
|
||||
{
|
||||
@@ -477,7 +495,7 @@ fs_vnode_ops gNFSv4VnodeOps = {
|
||||
NULL, // fs_preallocate()
|
||||
|
||||
/* file operations */
|
||||
NULL, // create()
|
||||
nfs4_create,
|
||||
nfs4_open,
|
||||
nfs4_close,
|
||||
nfs4_free_cookie,
|
||||
|
||||
Reference in New Issue
Block a user