From 20bd3ee165c505a6105c7ca16b707db2a479ee05 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Tue, 26 Jun 2012 16:43:37 +0200 Subject: [PATCH] nfs4: Add create() hook --- .../kernel/file_systems/nfs4/Inode.cpp | 206 +++++++++++++++--- src/add-ons/kernel/file_systems/nfs4/Inode.h | 2 + .../kernel/file_systems/nfs4/NFS4Defs.h | 9 +- .../file_systems/nfs4/RequestBuilder.cpp | 8 +- .../kernel/file_systems/nfs4/RequestBuilder.h | 4 +- .../file_systems/nfs4/kernel_interface.cpp | 20 +- 6 files changed, 213 insertions(+), 36 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index a73837e37d..ae11bb6276 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -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(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; } diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h b/src/add-ons/kernel/file_systems/nfs4/Inode.h index 89caa2c39c..ae649add73 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -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, diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h index 548992be91..7cb8e801d2 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h @@ -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, diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp index e45eafb6b8..eebbc0f20d 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp @@ -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: diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h index 8101cd4059..e864576f7d 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h @@ -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); diff --git a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp index 8a5781cac8..fd24f6fa56 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -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(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,