From 8fe02d0c04e24c9b257d9e966c04b745f5ed254b Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Thu, 24 May 2012 18:00:50 +0200 Subject: [PATCH 001/252] nfs4: Initial commit Empty file system with only mounting supported. --- build/jam/BuildSetup | 1 + build/jam/HaikuImage | 2 +- src/add-ons/kernel/file_systems/Jamfile | 1 + src/add-ons/kernel/file_systems/nfs4/Jamfile | 7 ++ .../file_systems/nfs4/kernel_interface.cpp | 110 ++++++++++++++++++ 5 files changed, 120 insertions(+), 1 deletion(-) create mode 100644 src/add-ons/kernel/file_systems/nfs4/Jamfile create mode 100644 src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp diff --git a/build/jam/BuildSetup b/build/jam/BuildSetup index dd4a91d91e..b6fbcc1c5b 100644 --- a/build/jam/BuildSetup +++ b/build/jam/BuildSetup @@ -1287,6 +1287,7 @@ if $(HAIKU_NO_WERROR) != 1 { EnableWerror src add-ons kernel file_systems layers ; EnableWerror src add-ons kernel file_systems netfs ; EnableWerror src add-ons kernel file_systems nfs ; + EnableWerror src add-ons kernel file_systems nfs4 ; # EnableWerror src add-ons kernel file_systems ntfs ; EnableWerror src add-ons kernel file_systems packagefs ; EnableWerror src add-ons kernel file_systems ramfs ; diff --git a/build/jam/HaikuImage b/build/jam/HaikuImage index ffc8d7ea74..0f44294dcd 100644 --- a/build/jam/HaikuImage +++ b/build/jam/HaikuImage @@ -194,7 +194,7 @@ SYSTEM_ADD_ONS_DRIVERS_POWER = $(X86_ONLY)acpi_button ; SYSTEM_ADD_ONS_BUS_MANAGERS = $(ATA_ONLY)ata pci $(X86_ONLY)ps2 $(X86_ONLY)isa $(IDE_ONLY)ide scsi config_manager agp_gart usb firewire $(X86_ONLY)acpi ; -SYSTEM_ADD_ONS_FILE_SYSTEMS = bfs btrfs cdda exfat ext2 fat iso9660 nfs +SYSTEM_ADD_ONS_FILE_SYSTEMS = bfs btrfs cdda exfat ext2 fat iso9660 nfs nfs4 attribute_overlay write_overlay ntfs reiserfs udf googlefs ; # wifi firmware diff --git a/src/add-ons/kernel/file_systems/Jamfile b/src/add-ons/kernel/file_systems/Jamfile index 24fe5eb6a1..25bb03651a 100644 --- a/src/add-ons/kernel/file_systems/Jamfile +++ b/src/add-ons/kernel/file_systems/Jamfile @@ -11,6 +11,7 @@ SubInclude HAIKU_TOP src add-ons kernel file_systems googlefs ; SubInclude HAIKU_TOP src add-ons kernel file_systems iso9660 ; SubInclude HAIKU_TOP src add-ons kernel file_systems netfs ; SubInclude HAIKU_TOP src add-ons kernel file_systems nfs ; +SubInclude HAIKU_TOP src add-ons kernel file_systems nfs4 ; SubInclude HAIKU_TOP src add-ons kernel file_systems ntfs ; SubInclude HAIKU_TOP src add-ons kernel file_systems packagefs ; SubInclude HAIKU_TOP src add-ons kernel file_systems ramfs ; diff --git a/src/add-ons/kernel/file_systems/nfs4/Jamfile b/src/add-ons/kernel/file_systems/nfs4/Jamfile new file mode 100644 index 0000000000..573415bf6b --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/Jamfile @@ -0,0 +1,7 @@ +SubDir HAIKU_TOP src add-ons kernel file_systems nfs4 ; + +UsePrivateHeaders kernel ; + +KernelAddon nfs4 : + kernel_interface.cpp +; diff --git a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp new file mode 100644 index 0000000000..e76a4b7375 --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -0,0 +1,110 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ + + +#include + + +extern fs_volume_ops gNFSv4VolumeOps; +extern fs_vnode_ops gNFSv4VnodeOps; + +extern "C" void +dprintf(const char* format, ...); + + +static status_t +nfs4_mount(fs_volume* volume, const char* device, uint32 flags, + const char* args, ino_t* _rootVnodeID) +{ + dprintf("NFS4 Mounting...\n"); + + volume->ops = &gNFSv4VolumeOps; + + status_t error = publish_vnode(volume, 0, (void*)0xdeadbeef, + &gNFSv4VnodeOps, S_IFDIR, 0); + if (error != B_OK) + return error; + + *_rootVnodeID = 0; + + dprintf("NFS4 Mounted\n"); + + return B_OK; +} + + +static status_t +nfs4_unmount(fs_volume* volume) +{ + dprintf("NFS4 Unmounting...\n"); + return B_OK; +} + + +static status_t +nfs4_put_vnode(fs_volume* volume, fs_vnode* vnode, bool reenter) +{ + return B_OK; +} + + +static status_t +nfs4_std_ops(int32 op, ...) +{ + switch (op) { + case B_MODULE_INIT: + dprintf("NFS4 Init\n"); + return B_OK; + + case B_MODULE_UNINIT: + dprintf("NFS4 Uninit\n"); + return B_OK; + + default: + return B_ERROR; + } +} + + +fs_volume_ops gNFSv4VolumeOps = { + &nfs4_unmount +}; + +fs_vnode_ops gNFSv4VnodeOps = { + NULL, // lookup() + NULL, // get_vnode_name() + &nfs4_put_vnode +}; + +static file_system_module_info sNFSv4ModuleInfo = { + { + "file_systems/nfs4" B_CURRENT_FS_API_VERSION, + 0, + nfs4_std_ops, + }, + + "nfs4", // short_name + "Network File System version 4", // pretty_name + + // DDM flags + 0, + + // scanning + NULL, // identify_partition() + NULL, // scan_partition() + NULL, // free_identify_partition_cookie() + NULL, // free_partition_content_cookie() + + &nfs4_mount, +}; + +module_info* modules[] = { + (module_info* )&sNFSv4ModuleInfo, + NULL, +}; + From e4977f2046fcdaeee40c869a3bce8e391c87b7ad Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Thu, 24 May 2012 20:19:40 +0200 Subject: [PATCH 002/252] nfs4: Add network code Connection class supports sending and receiving RPC data using either TCP or UDP as a transport protocol. --- .../kernel/file_systems/nfs4/Connection.cpp | 255 ++++++++++++++++++ .../kernel/file_systems/nfs4/Connection.h | 88 ++++++ src/add-ons/kernel/file_systems/nfs4/Jamfile | 1 + .../file_systems/nfs4/kernel_interface.cpp | 10 + 4 files changed, 354 insertions(+) create mode 100644 src/add-ons/kernel/file_systems/nfs4/Connection.cpp create mode 100644 src/add-ons/kernel/file_systems/nfs4/Connection.h diff --git a/src/add-ons/kernel/file_systems/nfs4/Connection.cpp b/src/add-ons/kernel/file_systems/nfs4/Connection.cpp new file mode 100644 index 0000000000..23f402bdd7 --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/Connection.cpp @@ -0,0 +1,255 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ + + +#include "Connection.h" + +#include +#include +#include +#include + +#include +#include + + +#define LAST_FRAGMENT 0x80000000 +#define MAX_PACKET_SIZE 65535 + + +KSOCKET_MODULE_DECL; + + +Connection::Connection(const sockaddr_in& addr, Transport proto, bool markers) + : + fSock(-1), + fUseMarkers(markers), + fProtocol(proto), + fServerAddress(addr) +{ + mutex_init(&fSockLock, NULL); +} + + +Connection::~Connection() +{ + kclosesocket(fSock); + mutex_destroy(&fSockLock); +} + + +status_t +Connection::_SendStream(const void* buffer, uint32 size) +{ + status_t result; + + uint32* buf = (uint32*)malloc(size + sizeof(uint32)); + if (buf == NULL) + return B_NO_MEMORY; + + buf[0] = htonl(size | LAST_FRAGMENT); + memcpy(buf + 1, buffer, size); + + // More than one threads may send data and ksend is allowed to send partial + // data. Need a lock here. + uint32 sent = 0; + mutex_lock(&fSockLock); + do { + result = ksend(fSock, buf + sent, size + sizeof(uint32) - sent, 0); + sent += result; + } while (result > 0 && sent < size + sizeof(uint32)); + mutex_unlock(&fSockLock); + if (result < 0) { + result = errno; + free(buf); + return result; + } else if (result == 0) { + free(buf); + return B_IO_ERROR; + } + + free(buf); + return B_OK; +} + + +status_t +Connection::_SendPacket(const void* buffer, uint32 size) +{ + // send on DGRAM sockets is atomic. No need to lock. + status_t result = ksend(fSock, buffer, size, 0); + if (result < 0) + return errno; + + return B_OK; +} + + +status_t +Connection::_ReceiveStream(void** pbuffer, uint32* psize) +{ + status_t result; + + int32 size = 0; + void* buffer = NULL; + + int32 record_size; + bool last_one; + do { + // There is only one listener thread per connection. No need to lock. + uint32 received = 0; + do { + result = krecv(fSock, &record_size + received, + sizeof(record_size) - received, 0); + received += result; + } while (result > 0 && received < sizeof(record_size)); + if (result < 0) { + result = errno; + free(buffer); + return result; + } else if (result == 0) { + free(buffer); + return ECONNABORTED; + } + + record_size = ntohl(record_size); + last_one = record_size < 0; + record_size &= LAST_FRAGMENT - 1; + + void* ptr = realloc(buffer, size + record_size); + if (ptr == NULL) { + free(buffer); + return B_NO_MEMORY; + } else + buffer = ptr; + + received = 0; + do { + result = krecv(fSock, (uint8*)buffer + size + received, + record_size - received, 0); + received += result; + } while (result > 0 && received < sizeof(record_size)); + if (result < 0) { + result = errno; + free(buffer); + return result; + } + + size += record_size; + } while (!last_one); + + + *pbuffer = buffer; + *psize = size; + + return B_OK; +} + + +status_t +Connection::_ReceivePacket(void** pbuffer, uint32* psize) +{ + status_t result; + int32 size = MAX_PACKET_SIZE; + void* buffer = malloc(size); + + if (buffer == NULL) + return B_NO_MEMORY; + + // There is only one listener thread per connection. No need to lock. + size = krecv(fSock, buffer, size, 0); + if (size < 0) { + result = errno; + free(buffer); + return result; + } + + *pbuffer = buffer; + *psize = size; + + return B_OK; +} + + +status_t +Connection::Connect(Connection **pconn, const ServerAddress& id) +{ + struct sockaddr_in addr; + + memset(&addr, 0, sizeof(addr)); + addr.sin_len = sizeof(struct sockaddr_in); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htonl(id.fAddress); + addr.sin_port = htons(id.fPort); + + Connection* conn = new(std::nothrow) Connection(addr, id.fProtocol, + id.fProtocol == ProtocolTCP); + if (conn == NULL) + return B_NO_MEMORY; + + status_t result = conn->_Connect(); + if (result != B_OK) { + delete conn; + return result; + } + + *pconn = conn; + + return B_OK; +} + + +status_t +Connection::_Connect() +{ + switch (fProtocol) { + case ProtocolTCP: + fSock = ksocket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + break; + case ProtocolUDP: + fSock = ksocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + break; + default: + return B_BAD_VALUE; + } + if (fSock < 0) + return errno; + + status_t result = kconnect(fSock, (struct sockaddr*)&fServerAddress, + fServerAddress.sin_len); + if (result < 0) { + result = errno; + kclosesocket(fSock); + return result; + } + + return B_OK; +} + + +status_t +Connection::Reconnect() +{ + kclosesocket(fSock); + return _Connect(); +} + + +status_t +Connection::Init() +{ + return ksocket_init(); +} + + +status_t +Connection::CleanUp() +{ + return ksocket_cleanup(); +} + diff --git a/src/add-ons/kernel/file_systems/nfs4/Connection.h b/src/add-ons/kernel/file_systems/nfs4/Connection.h new file mode 100644 index 0000000000..6ac07d318a --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/Connection.h @@ -0,0 +1,88 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ +#ifndef CONNECTION_H +#define CONNECTION_H + + +#include + +#include +#include + + +enum Transport { + ProtocolTCP = 6, + ProtocolUDP = 11 +}; + +struct ServerAddress { + uint32 fAddress; + uint16 fPort; + Transport fProtocol; + + bool operator==(const ServerAddress& x); + bool operator<(const ServerAddress& x); +}; + +class Connection { +public: + static status_t Connect(Connection **conn, + const ServerAddress& id); + ~Connection(); + + inline status_t Send(const void* buffer, uint32 size); + inline status_t Receive(void** buffer, uint32* size); + + status_t Reconnect(); + + static status_t Init(); + static status_t CleanUp(); + +private: + Connection(const sockaddr_in& addr, + Transport proto, bool markers); + status_t _Connect(); + + status_t _SendStream(const void* buffer, uint32 size); + status_t _SendPacket(const void* buffer, uint32 size); + + status_t _ReceiveStream(void** buffer, uint32* size); + status_t _ReceivePacket(void** buffer, uint32* size); + + int fSock; + mutex fSockLock; + + const bool fUseMarkers; + + const Transport fProtocol; + const sockaddr_in fServerAddress; +}; + + +inline status_t +Connection::Send(const void* buffer, uint32 size) +{ + if (fUseMarkers) + return _SendStream(buffer, size); + else + return _SendPacket(buffer, size); +} + + +inline status_t +Connection::Receive(void** buffer, uint32* size) +{ + if (fUseMarkers) + return _ReceiveStream(buffer, size); + else + return _ReceivePacket(buffer, size); +} + + +#endif // CONNECTION_H + diff --git a/src/add-ons/kernel/file_systems/nfs4/Jamfile b/src/add-ons/kernel/file_systems/nfs4/Jamfile index 573415bf6b..7c16aa0e5c 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Jamfile +++ b/src/add-ons/kernel/file_systems/nfs4/Jamfile @@ -3,5 +3,6 @@ SubDir HAIKU_TOP src add-ons kernel file_systems nfs4 ; UsePrivateHeaders kernel ; KernelAddon nfs4 : + Connection.cpp kernel_interface.cpp ; 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 e76a4b7375..391678b406 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -9,6 +9,8 @@ #include +#include "Connection.h" + extern fs_volume_ops gNFSv4VolumeOps; extern fs_vnode_ops gNFSv4VnodeOps; @@ -56,13 +58,21 @@ nfs4_put_vnode(fs_volume* volume, fs_vnode* vnode, bool reenter) static status_t nfs4_std_ops(int32 op, ...) { + status_t result; + switch (op) { case B_MODULE_INIT: dprintf("NFS4 Init\n"); + result = Connection::Init(); + if (result != B_OK) + return result; return B_OK; case B_MODULE_UNINIT: dprintf("NFS4 Uninit\n"); + result = Connection::CleanUp(); + if (result != B_OK) + return result; return B_OK; default: From 42b2ae1c808df07d3ae33f5c66a744070f9316ce Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Fri, 25 May 2012 20:10:08 +0200 Subject: [PATCH 003/252] nfs4: Add XDR encoder and decoder Base classes XDR::Stream and classes XDR::WriteStream and XDR::ReadStream are added. They implement encoding and decoding XDR (RFC 4506) streams. All data types used by RPC and NFS4 are supported. --- src/add-ons/kernel/file_systems/nfs4/Jamfile | 1 + src/add-ons/kernel/file_systems/nfs4/XDR.cpp | 326 +++++++++++++++++++ src/add-ons/kernel/file_systems/nfs4/XDR.h | 156 +++++++++ 3 files changed, 483 insertions(+) create mode 100644 src/add-ons/kernel/file_systems/nfs4/XDR.cpp create mode 100644 src/add-ons/kernel/file_systems/nfs4/XDR.h diff --git a/src/add-ons/kernel/file_systems/nfs4/Jamfile b/src/add-ons/kernel/file_systems/nfs4/Jamfile index 7c16aa0e5c..bf19a10fc1 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Jamfile +++ b/src/add-ons/kernel/file_systems/nfs4/Jamfile @@ -5,4 +5,5 @@ UsePrivateHeaders kernel ; KernelAddon nfs4 : Connection.cpp kernel_interface.cpp + XDR.cpp ; diff --git a/src/add-ons/kernel/file_systems/nfs4/XDR.cpp b/src/add-ons/kernel/file_systems/nfs4/XDR.cpp new file mode 100644 index 0000000000..b5af847367 --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/XDR.cpp @@ -0,0 +1,326 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ + + +#include "XDR.h" + +#include +#include + +#include + + +using namespace XDR; + +Stream::Stream(void* buffer, uint32 size) + : + fBuffer(reinterpret_cast(buffer)), + fSize(size), + fPosition(0) +{ +} + + +Stream::~Stream() +{ +} + + +uint32 +Stream::_PositionToSize() const +{ + return fPosition * sizeof(uint32); +} + + +uint32 +Stream::_RealSize(uint32 size) const +{ + uint32 real_size = size; + if (real_size % 4 != 0) + real_size = ((real_size >> 2) + 1) << 2; + return real_size; +} + + +ReadStream::ReadStream(void* buffer, uint32 size) + : + Stream(buffer, size), + fEOF(false) +{ +} + + +ReadStream::~ReadStream() +{ +} + + +int32 +ReadStream::GetInt() +{ + if (_PositionToSize() >= fSize) { + fEOF = true; + return 0; + } + + return B_BENDIAN_TO_HOST_INT32(fBuffer[fPosition++]); +} + + +uint32 +ReadStream::GetUInt() +{ + if (_PositionToSize() >= fSize) { + fEOF = true; + return 0; + } + + return B_BENDIAN_TO_HOST_INT32(fBuffer[fPosition++]); +} + + +int64 +ReadStream::GetHyper() +{ + if (_PositionToSize() + sizeof(int64) > fSize) { + fEOF = true; + return 0; + } + + int64* ptr = reinterpret_cast(fBuffer + fPosition); + fPosition += 2; + + return B_BENDIAN_TO_HOST_INT64(*ptr); +} + + +uint64 +ReadStream::GetUHyper() +{ + if (_PositionToSize() + sizeof(uint64) > fSize) { + fEOF = true; + return 0; + } + + uint64* ptr = reinterpret_cast(fBuffer + fPosition); + fPosition += 2; + + return B_BENDIAN_TO_HOST_INT64(*ptr); +} + + +const char* +ReadStream::GetString() +{ + if (_PositionToSize() >= fSize) { + fEOF = true; + return NULL; + } + + uint32 size; + const void* ptr = GetOpaque(&size); + if (ptr == NULL) + return NULL; + + char* str = reinterpret_cast(malloc(size + 1)); + if (str == NULL) + return NULL; + + memcpy(str, ptr, size); + str[size] = 0; + + return str; +} + + +const void* +ReadStream::GetOpaque(uint32* size) +{ + if (_PositionToSize() >= fSize) { + fEOF = true; + return NULL; + } + + void* ptr = NULL; + uint32 s = GetUInt(); + if (s != 0) { + ptr = fBuffer + fPosition; + if (_PositionToSize() + s <= fSize) + fPosition += _RealSize(s) / sizeof(uint32); + else { + s = fSize - _PositionToSize(); + fPosition = fSize; + } + } + + if (size != NULL) + *size = s; + + return ptr; +} + + +WriteStream::WriteStream() + : + Stream(malloc(kInitialSize), kInitialSize), + fError(B_OK) +{ +} + + +WriteStream::WriteStream(const WriteStream& x) + : + Stream(malloc(x.fSize), x.fSize), + fError(x.fError) +{ + fPosition = x.fPosition; + memcpy(fBuffer, x.fBuffer, fSize); +} + + +WriteStream::~WriteStream() +{ + free(fBuffer); +} + + +status_t +WriteStream::InsertUInt(Stream::Position pos, uint32 x) +{ + if (pos * sizeof(uint32) >= fSize) { + fError = B_BAD_VALUE; + return B_BAD_VALUE; + } + + fBuffer[pos] = B_HOST_TO_BENDIAN_INT32(x); + return B_OK; +} + + +status_t +WriteStream::AddInt(int32 x) +{ + status_t err = _CheckResize(sizeof(int32)); + if (err != B_OK) + return err; + + fBuffer[fPosition++] = B_HOST_TO_BENDIAN_INT32(x); + return B_OK; +} + + +status_t +WriteStream::AddUInt(uint32 x) +{ + status_t err = _CheckResize(sizeof(uint32)); + if (err != B_OK) + return err; + + fBuffer[fPosition++] = B_HOST_TO_BENDIAN_INT32(x); + return B_OK; +} + + +status_t +WriteStream::AddHyper(int64 x) +{ + status_t err = _CheckResize(sizeof(int64)); + if (err != B_OK) + return err; + + int64* ptr = reinterpret_cast(fBuffer + fPosition); + *ptr = B_HOST_TO_BENDIAN_INT64(x); + fPosition += 2; + return B_OK; +} + + +status_t +WriteStream::AddUHyper(uint64 x) +{ + status_t err = _CheckResize(sizeof(uint64)); + if (err != B_OK) + return err; + + uint64* ptr = reinterpret_cast(fBuffer + fPosition); + *ptr = B_HOST_TO_BENDIAN_INT64(x); + fPosition += 2; + return B_OK; +} + + +status_t +WriteStream::AddString(const char* str, uint32 maxlen) +{ + uint32 len = strlen(str); + uint32 size = min_c(maxlen, len); + + return AddOpaque(str, size); +} + + +status_t +WriteStream::AddOpaque(const void *ptr, uint32 size) +{ + uint32 real_size = _RealSize(size); + status_t err = _CheckResize(real_size + sizeof(uint32)); + if (err != B_OK) + return err; + + AddUInt(size); + memset(fBuffer + fPosition, 0, real_size); + memcpy(fBuffer + fPosition, ptr, size); + fPosition += real_size / sizeof(int32); + + return B_OK; +} + + +status_t +WriteStream::AddOpaque(const WriteStream& stream) +{ + return AddOpaque(stream.GetBuffer(), stream.GetSize()); +} + + +status_t +WriteStream::Append(const WriteStream& stream) +{ + uint32 size = stream.GetSize(); + status_t err = _CheckResize(size); + if (err != B_OK) + return err; + + memcpy(fBuffer + fPosition, stream.GetBuffer(), size); + fPosition += size / sizeof(int32); + + return B_OK; +} + + +status_t +WriteStream::_CheckResize(uint32 size) +{ + if (_PositionToSize() + size <= fSize) + return B_OK; + + uint32 new_size = max_c(fSize * 2, fPosition * sizeof(uint32) + size); + + void* ptr = realloc(fBuffer, new_size); + if (ptr == NULL) { + fError = B_NO_MEMORY; + return B_NO_MEMORY; + } + + fBuffer = reinterpret_cast(ptr); + fSize = new_size; + + return B_OK; +} + diff --git a/src/add-ons/kernel/file_systems/nfs4/XDR.h b/src/add-ons/kernel/file_systems/nfs4/XDR.h new file mode 100644 index 0000000000..05bdaf2842 --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/XDR.h @@ -0,0 +1,156 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ +#ifndef XDR_H +#define XDR_H + + +#include + + +namespace XDR { + +class Stream { +public: + typedef uint32 Position; + + virtual ~Stream(); + + inline const void* GetBuffer() const; + inline Position GetCurrent() const; + +protected: + Stream(void* buffer, uint32 size); + + inline uint32 _PositionToSize() const; + inline uint32 _RealSize(uint32 size) const; + + uint32* fBuffer; + uint32 fSize; + Position fPosition; +}; + +class ReadStream : public Stream { +public: + ReadStream(void* buffer, uint32 size); + virtual ~ReadStream(); + + inline int GetSize() const; + + int32 GetInt(); + uint32 GetUInt(); + int64 GetHyper(); + uint64 GetUHyper(); + + inline bool GetBoolean(); + + const char* GetString(); + + const void* GetOpaque(uint32* size); + + inline bool IsEOF() const; + +private: + bool fEOF; +}; + +class WriteStream : public Stream { +public: + WriteStream(); + WriteStream(const WriteStream& x); + virtual ~WriteStream(); + + inline int GetSize() const; + + status_t InsertUInt(Stream::Position pos, uint32 x); + + status_t AddInt(int32 x); + status_t AddUInt(uint32 x); + status_t AddHyper(int64 x); + status_t AddUHyper(uint64 x); + + inline status_t AddBoolean(bool x); + + status_t AddString(const char* str, uint32 maxlen); + + status_t AddOpaque(const void* ptr, uint32 size); + status_t AddOpaque(const WriteStream& stream); + + status_t Append(const WriteStream& stream); + + inline status_t GetError() const; + +private: + status_t _CheckResize(uint32 size); + + status_t fError; + + static const uint32 kInitialSize = 64; +}; + + +inline const void* +Stream::GetBuffer() const +{ + return fBuffer; +} + + +inline Stream::Position +Stream::GetCurrent() const +{ + return fPosition; +} + + +inline int +ReadStream::GetSize() const +{ + return fSize; +} + + +inline bool +ReadStream::IsEOF() const +{ + return fEOF; +} + + +inline bool +ReadStream::GetBoolean() +{ + return GetInt() != 0; +} + + +inline int +WriteStream::GetSize() const +{ + return fPosition * sizeof(uint32); +} + + +inline status_t +WriteStream::AddBoolean(bool x) +{ + return AddInt(static_cast(x)); +} + + +inline status_t +WriteStream::GetError() const +{ + return fError; +} + + +} // namespace XDR + + +#endif // XDR_H + From 313da82b9fa72e56ce424852a9dee444bfbf7bfc Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Fri, 25 May 2012 20:32:10 +0200 Subject: [PATCH 004/252] nfs4: Add call generation code including authentication RPC::Call generates a RPC call using provided RPC::Auth objects. RPC::Auth supports AUTH_NONE and AUTH_SYS authentication protocols. --- src/add-ons/kernel/file_systems/nfs4/Jamfile | 2 + .../kernel/file_systems/nfs4/RPCAuth.cpp | 89 +++++++++++++++++++ .../kernel/file_systems/nfs4/RPCAuth.h | 46 ++++++++++ .../kernel/file_systems/nfs4/RPCCall.cpp | 77 ++++++++++++++++ .../kernel/file_systems/nfs4/RPCCall.h | 46 ++++++++++ 5 files changed, 260 insertions(+) create mode 100644 src/add-ons/kernel/file_systems/nfs4/RPCAuth.cpp create mode 100644 src/add-ons/kernel/file_systems/nfs4/RPCAuth.h create mode 100644 src/add-ons/kernel/file_systems/nfs4/RPCCall.cpp create mode 100644 src/add-ons/kernel/file_systems/nfs4/RPCCall.h diff --git a/src/add-ons/kernel/file_systems/nfs4/Jamfile b/src/add-ons/kernel/file_systems/nfs4/Jamfile index bf19a10fc1..f9d1a67401 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Jamfile +++ b/src/add-ons/kernel/file_systems/nfs4/Jamfile @@ -5,5 +5,7 @@ UsePrivateHeaders kernel ; KernelAddon nfs4 : Connection.cpp kernel_interface.cpp + RPCAuth.cpp + RPCCall.cpp XDR.cpp ; diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCAuth.cpp b/src/add-ons/kernel/file_systems/nfs4/RPCAuth.cpp new file mode 100644 index 0000000000..f7f2a1f4c9 --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/RPCAuth.cpp @@ -0,0 +1,89 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ + + +#include "RPCAuth.h" + +#include +#include +#include + +#include +#include + + +using namespace RPC; + + +Auth::Auth() +{ +} + + +const Auth* +Auth::CreateNone() +{ + Auth* auth = new(std::nothrow) Auth; + if (auth == NULL) + return NULL; + + auth->fStream.AddInt(AUTH_NONE); + auth->fStream.AddOpaque(NULL, 0); + if (auth->fStream.GetError() != B_OK) { + delete auth; + return NULL; + } + + return auth; +} + + +const Auth* +Auth::CreateSys() +{ + Auth* auth = new(std::nothrow) Auth; + if (auth == NULL) + return NULL; + + XDR::WriteStream xdr; + xdr.AddUInt(time(NULL)); + + char hostname[255]; + //if (gethostname(hostname, 255) < 0) + strcpy(hostname, "unknown"); + xdr.AddString(hostname, 255); + + xdr.AddUInt(getuid()); + xdr.AddUInt(getgid()); + + int count = getgroups(0, NULL); + gid_t* groups = (gid_t*)malloc(count * sizeof(gid_t)); + int len = getgroups(count, groups); + if (len > 0) { + len = min_c(len, 16); + xdr.AddUInt(len); + for (int i = 0; i < len; i++) + xdr.AddUInt((uint32)groups[i]); + } else + xdr.AddUInt(0); + free(groups); + if (xdr.GetError() != B_OK) { + delete auth; + return NULL; + } + + auth->fStream.AddInt(AUTH_SYS); + auth->fStream.AddOpaque(xdr); + if (auth->fStream.GetError() != B_OK) { + delete auth; + return NULL; + } + + return auth; +} + diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCAuth.h b/src/add-ons/kernel/file_systems/nfs4/RPCAuth.h new file mode 100644 index 0000000000..1e79e3dba1 --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/RPCAuth.h @@ -0,0 +1,46 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ +#ifndef RPCAUTH_H +#define RPCAUTH_H + + +#include "XDR.h" + + +namespace RPC { + +enum auth_flavour { + AUTH_NONE = 0, + AUTH_SYS = 1 +}; + +class Auth { +public: + inline const XDR::WriteStream& GetStream() const; + + static const Auth* CreateNone(); + static const Auth* CreateSys(); + +private: + Auth(); + + XDR::WriteStream fStream; +}; + + +inline const XDR::WriteStream& +Auth::GetStream() const +{ + return fStream; +} + +} // namespace RPC + + +#endif // RPCAUTH_H + diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCCall.cpp b/src/add-ons/kernel/file_systems/nfs4/RPCCall.cpp new file mode 100644 index 0000000000..9800823659 --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/RPCCall.cpp @@ -0,0 +1,77 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ + + +#include "RPCCall.h" + +#include + + +using namespace RPC; + +enum { + CALL = 0 +}; + +#define VERSION 2 + +enum { + PROGRAM_NFS = 100003 +}; + +#define NFS_VERSION 4 + + +Call::Call() +{ +} + + +Call* +Call::Create(uint32 proc, const Auth* creds, const Auth* ver) +{ + Call* call = new(std::nothrow) Call; + if (call == NULL) + return NULL; + + // XID will be determined and set by RPC::Server + call->fXIDPosition = call->fStream.GetCurrent(); + call->fStream.AddUInt(0); + + call->fStream.AddInt(CALL); + call->fStream.AddUInt(VERSION); + call->fStream.AddUInt(PROGRAM_NFS); + call->fStream.AddUInt(NFS_VERSION); + call->fStream.AddUInt(proc); + + call->fStream.Append(creds->GetStream()); + delete creds; + + call->fStream.Append(ver->GetStream()); + delete ver; + + if (call->fStream.GetError() != B_OK) { + delete call; + return NULL; + } + + return call; +} + + +Call::~Call() +{ +} + + +void +Call::SetXID(uint32 xid) +{ + fStream.InsertUInt(fXIDPosition, xid); +} + diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCCall.h b/src/add-ons/kernel/file_systems/nfs4/RPCCall.h new file mode 100644 index 0000000000..b5d92cebb3 --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/RPCCall.h @@ -0,0 +1,46 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ +#ifndef RPCCALL_H +#define RPCCALL_H + + +#include "RPCAuth.h" +#include "XDR.h" + + +namespace RPC { + +class Call { +public: + static Call* Create(uint32 proc, const Auth* creds, + const Auth* ver); + ~Call(); + + void SetXID(uint32 x); + + inline XDR::WriteStream& GetStream(); + +private: + Call(); + + XDR::Stream::Position fXIDPosition; + + XDR::WriteStream fStream; +}; + + +inline XDR::WriteStream& +Call::GetStream() +{ + return fStream; +} + +} // namespace RPC + + +#endif // RPCCALL_H From da59bc46d9a6a09562dca3b916dce0383c97fa97 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Fri, 25 May 2012 20:47:03 +0200 Subject: [PATCH 005/252] nfs4: Add stub RPC reply code RPC::Reply interprets incoming RPC replies. Currently only XID is read. --- src/add-ons/kernel/file_systems/nfs4/Jamfile | 1 + .../kernel/file_systems/nfs4/RPCReply.cpp | 38 ++++++++++++ .../kernel/file_systems/nfs4/RPCReply.h | 60 +++++++++++++++++++ 3 files changed, 99 insertions(+) create mode 100644 src/add-ons/kernel/file_systems/nfs4/RPCReply.cpp create mode 100644 src/add-ons/kernel/file_systems/nfs4/RPCReply.h diff --git a/src/add-ons/kernel/file_systems/nfs4/Jamfile b/src/add-ons/kernel/file_systems/nfs4/Jamfile index f9d1a67401..360f9ec6d3 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Jamfile +++ b/src/add-ons/kernel/file_systems/nfs4/Jamfile @@ -7,5 +7,6 @@ KernelAddon nfs4 : kernel_interface.cpp RPCAuth.cpp RPCCall.cpp + RPCReply.cpp XDR.cpp ; diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCReply.cpp b/src/add-ons/kernel/file_systems/nfs4/RPCReply.cpp new file mode 100644 index 0000000000..b09728a4e3 --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/RPCReply.cpp @@ -0,0 +1,38 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ + + +#include "RPCReply.h" + +#include + + +using namespace RPC; + + +Reply::Reply(void *buffer, int size) + : + fError(B_OK), + fStream(buffer, size), + fBuffer(buffer) +{ + fXID = fStream.GetUInt(); +#if 0 + int32 type = fStream.GetInt(); + int32 state = fStream.GetInt(); + int32 auth = fStream.GetInt(); + fStream.GetOpaque(NULL); +#endif +} + + +Reply::~Reply() +{ + free(fBuffer); +} + diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCReply.h b/src/add-ons/kernel/file_systems/nfs4/RPCReply.h new file mode 100644 index 0000000000..a383651ea3 --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/RPCReply.h @@ -0,0 +1,60 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ +#ifndef RPCREPLY_H +#define RPCREPLY_H + + +#include "XDR.h" + + +namespace RPC { + +class Reply { +public: + Reply(void *buffer, int size); + ~Reply(); + + inline uint32 GetXID(); + + inline status_t GetError(); + inline XDR::ReadStream& GetStream(); + +private: + uint32 fXID; + + status_t fError; + + XDR::ReadStream fStream; + void* fBuffer; +}; + +inline uint32 +Reply::GetXID() +{ + return fXID; +} + + +inline status_t +Reply::GetError() +{ + return fError; +} + + +inline XDR::ReadStream& +Reply::GetStream() +{ + return fStream; +} + +} // namespace RPC + + +#endif // RPCREPLY_H + From bb7c7ca2c42957001ad102b7b7e02362802ed8d2 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Fri, 25 May 2012 22:16:00 +0200 Subject: [PATCH 006/252] nfs4: Remove unnecessary 'Get' prefixes from accessor methods --- .../kernel/file_systems/nfs4/RPCAuth.cpp | 6 +++--- .../kernel/file_systems/nfs4/RPCAuth.h | 4 ++-- .../kernel/file_systems/nfs4/RPCCall.cpp | 8 ++++---- .../kernel/file_systems/nfs4/RPCCall.h | 4 ++-- .../kernel/file_systems/nfs4/RPCReply.h | 8 ++++---- src/add-ons/kernel/file_systems/nfs4/XDR.cpp | 6 +++--- src/add-ons/kernel/file_systems/nfs4/XDR.h | 20 +++++++++---------- 7 files changed, 28 insertions(+), 28 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCAuth.cpp b/src/add-ons/kernel/file_systems/nfs4/RPCAuth.cpp index f7f2a1f4c9..6c6f1ba5d7 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RPCAuth.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RPCAuth.cpp @@ -34,7 +34,7 @@ Auth::CreateNone() auth->fStream.AddInt(AUTH_NONE); auth->fStream.AddOpaque(NULL, 0); - if (auth->fStream.GetError() != B_OK) { + if (auth->fStream.Error() != B_OK) { delete auth; return NULL; } @@ -72,14 +72,14 @@ Auth::CreateSys() } else xdr.AddUInt(0); free(groups); - if (xdr.GetError() != B_OK) { + if (xdr.Error() != B_OK) { delete auth; return NULL; } auth->fStream.AddInt(AUTH_SYS); auth->fStream.AddOpaque(xdr); - if (auth->fStream.GetError() != B_OK) { + if (auth->fStream.Error() != B_OK) { delete auth; return NULL; } diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCAuth.h b/src/add-ons/kernel/file_systems/nfs4/RPCAuth.h index 1e79e3dba1..81a127f3ab 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RPCAuth.h +++ b/src/add-ons/kernel/file_systems/nfs4/RPCAuth.h @@ -21,7 +21,7 @@ enum auth_flavour { class Auth { public: - inline const XDR::WriteStream& GetStream() const; + inline const XDR::WriteStream& Stream() const; static const Auth* CreateNone(); static const Auth* CreateSys(); @@ -34,7 +34,7 @@ private: inline const XDR::WriteStream& -Auth::GetStream() const +Auth::Stream() const { return fStream; } diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCCall.cpp b/src/add-ons/kernel/file_systems/nfs4/RPCCall.cpp index 9800823659..323e7f1f2e 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RPCCall.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RPCCall.cpp @@ -40,7 +40,7 @@ Call::Create(uint32 proc, const Auth* creds, const Auth* ver) return NULL; // XID will be determined and set by RPC::Server - call->fXIDPosition = call->fStream.GetCurrent(); + call->fXIDPosition = call->fStream.Current(); call->fStream.AddUInt(0); call->fStream.AddInt(CALL); @@ -49,13 +49,13 @@ Call::Create(uint32 proc, const Auth* creds, const Auth* ver) call->fStream.AddUInt(NFS_VERSION); call->fStream.AddUInt(proc); - call->fStream.Append(creds->GetStream()); + call->fStream.Append(creds->Stream()); delete creds; - call->fStream.Append(ver->GetStream()); + call->fStream.Append(ver->Stream()); delete ver; - if (call->fStream.GetError() != B_OK) { + if (call->fStream.Error() != B_OK) { delete call; return NULL; } diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCCall.h b/src/add-ons/kernel/file_systems/nfs4/RPCCall.h index b5d92cebb3..f1739bd4d1 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RPCCall.h +++ b/src/add-ons/kernel/file_systems/nfs4/RPCCall.h @@ -23,7 +23,7 @@ public: void SetXID(uint32 x); - inline XDR::WriteStream& GetStream(); + inline XDR::WriteStream& Stream(); private: Call(); @@ -35,7 +35,7 @@ private: inline XDR::WriteStream& -Call::GetStream() +Call::Stream() { return fStream; } diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCReply.h b/src/add-ons/kernel/file_systems/nfs4/RPCReply.h index a383651ea3..6d688d89bf 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RPCReply.h +++ b/src/add-ons/kernel/file_systems/nfs4/RPCReply.h @@ -21,8 +21,8 @@ public: inline uint32 GetXID(); - inline status_t GetError(); - inline XDR::ReadStream& GetStream(); + inline status_t Error(); + inline XDR::ReadStream& Stream(); private: uint32 fXID; @@ -41,14 +41,14 @@ Reply::GetXID() inline status_t -Reply::GetError() +Reply::Error() { return fError; } inline XDR::ReadStream& -Reply::GetStream() +Reply::Stream() { return fStream; } diff --git a/src/add-ons/kernel/file_systems/nfs4/XDR.cpp b/src/add-ons/kernel/file_systems/nfs4/XDR.cpp index b5af847367..6d6dd0d90e 100644 --- a/src/add-ons/kernel/file_systems/nfs4/XDR.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/XDR.cpp @@ -285,19 +285,19 @@ WriteStream::AddOpaque(const void *ptr, uint32 size) status_t WriteStream::AddOpaque(const WriteStream& stream) { - return AddOpaque(stream.GetBuffer(), stream.GetSize()); + return AddOpaque(stream.Buffer(), stream.Size()); } status_t WriteStream::Append(const WriteStream& stream) { - uint32 size = stream.GetSize(); + uint32 size = stream.Size(); status_t err = _CheckResize(size); if (err != B_OK) return err; - memcpy(fBuffer + fPosition, stream.GetBuffer(), size); + memcpy(fBuffer + fPosition, stream.Buffer(), size); fPosition += size / sizeof(int32); return B_OK; diff --git a/src/add-ons/kernel/file_systems/nfs4/XDR.h b/src/add-ons/kernel/file_systems/nfs4/XDR.h index 05bdaf2842..00cfce3a9e 100644 --- a/src/add-ons/kernel/file_systems/nfs4/XDR.h +++ b/src/add-ons/kernel/file_systems/nfs4/XDR.h @@ -20,8 +20,8 @@ public: virtual ~Stream(); - inline const void* GetBuffer() const; - inline Position GetCurrent() const; + inline const void* Buffer() const; + inline Position Current() const; protected: Stream(void* buffer, uint32 size); @@ -39,7 +39,7 @@ public: ReadStream(void* buffer, uint32 size); virtual ~ReadStream(); - inline int GetSize() const; + inline int Size() const; int32 GetInt(); uint32 GetUInt(); @@ -64,7 +64,7 @@ public: WriteStream(const WriteStream& x); virtual ~WriteStream(); - inline int GetSize() const; + inline int Size() const; status_t InsertUInt(Stream::Position pos, uint32 x); @@ -82,7 +82,7 @@ public: status_t Append(const WriteStream& stream); - inline status_t GetError() const; + inline status_t Error() const; private: status_t _CheckResize(uint32 size); @@ -94,21 +94,21 @@ private: inline const void* -Stream::GetBuffer() const +Stream::Buffer() const { return fBuffer; } inline Stream::Position -Stream::GetCurrent() const +Stream::Current() const { return fPosition; } inline int -ReadStream::GetSize() const +ReadStream::Size() const { return fSize; } @@ -129,7 +129,7 @@ ReadStream::GetBoolean() inline int -WriteStream::GetSize() const +WriteStream::Size() const { return fPosition * sizeof(uint32); } @@ -143,7 +143,7 @@ WriteStream::AddBoolean(bool x) inline status_t -WriteStream::GetError() const +WriteStream::Error() const { return fError; } From 274145b3ea982354ad13960d5055a5d6848b0ab7 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Fri, 25 May 2012 22:27:09 +0200 Subject: [PATCH 007/252] nfs4: Add ServerAddress comparators --- .../kernel/file_systems/nfs4/Connection.cpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/add-ons/kernel/file_systems/nfs4/Connection.cpp b/src/add-ons/kernel/file_systems/nfs4/Connection.cpp index 23f402bdd7..094dfe6da3 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Connection.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Connection.cpp @@ -25,6 +25,23 @@ KSOCKET_MODULE_DECL; +bool +ServerAddress::operator==(const ServerAddress& x) +{ + return fAddress == x.fAddress && fPort == x.fPort + && fProtocol == x.fProtocol; +} + +bool +ServerAddress::operator<(const ServerAddress& x) +{ + return fAddress < x.fAddress || + (fAddress == x.fAddress && fPort < x.fPort) || + (fAddress == x.fAddress && fPort == x.fPort && + fProtocol < x.fProtocol); +} + + Connection::Connection(const sockaddr_in& addr, Transport proto, bool markers) : fSock(-1), From b35311f1ba07855a6152bb248b1758567f52e224 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Fri, 25 May 2012 22:43:23 +0200 Subject: [PATCH 008/252] nfs4: Add RPC main communication code RPC::Server represents a server client is connected to. RPC::RequestManager stores all call that have been sent but no answer was received so far. RPC::ServerManager is responsible for reusing connections to the servers and closing them when no longer needed. --- src/add-ons/kernel/file_systems/nfs4/Jamfile | 1 + .../kernel/file_systems/nfs4/RPCServer.cpp | 349 ++++++++++++++++++ .../kernel/file_systems/nfs4/RPCServer.h | 104 ++++++ 3 files changed, 454 insertions(+) create mode 100644 src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp create mode 100644 src/add-ons/kernel/file_systems/nfs4/RPCServer.h diff --git a/src/add-ons/kernel/file_systems/nfs4/Jamfile b/src/add-ons/kernel/file_systems/nfs4/Jamfile index 360f9ec6d3..db1386b800 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Jamfile +++ b/src/add-ons/kernel/file_systems/nfs4/Jamfile @@ -8,5 +8,6 @@ KernelAddon nfs4 : RPCAuth.cpp RPCCall.cpp RPCReply.cpp + RPCServer.cpp XDR.cpp ; diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp b/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp new file mode 100644 index 0000000000..031f0051cc --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp @@ -0,0 +1,349 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ + + +#include "RPCServer.h" + +#include + +#include "RPCReply.h" + + +using namespace RPC; + + +RequestManager::RequestManager() + : + fQueueHead(NULL), + fQueueTail(NULL) +{ + mutex_init(&fLock, NULL); +} + + +RequestManager::~RequestManager() +{ + mutex_destroy(&fLock); +} + + +void +RequestManager::AddRequest(Request* req) +{ + mutex_lock(&fLock); + if (fQueueTail != NULL) + fQueueTail->fNext = req; + else + fQueueHead = req; + fQueueTail = req; + mutex_unlock(&fLock); +} + + +Request* +RequestManager::FindRequest(uint32 xid) +{ + mutex_lock(&fLock); + Request* req = fQueueHead; + Request* prev = NULL; + while (req != NULL) { + if (req->fXID == xid) { + if (prev != NULL) + prev->fNext = req->fNext; + if (fQueueTail == req) + fQueueTail = prev; + if (fQueueHead == req) + fQueueHead = req->fNext; + mutex_unlock(&fLock); + dprintf("Found %x %x\n", (unsigned int)fQueueHead, (unsigned int)fQueueTail); + + return req; + } + + prev = req; + req = req->fNext; + } + dprintf("Nothing found\n"); + mutex_unlock(&fLock); + + return NULL; +} + + +Server::Server(Connection* conn) + : + fConnection(conn), + fXID(rand() << 1) +{ + _StartListening(); +} + + +Server::~Server() +{ + fThreadCancel = true; + + delete fConnection; + + status_t result; + wait_for_thread(fThread, &result); +} + + +status_t +Server::_StartListening() +{ + dprintf("new thread\n"); + fThreadCancel = false; + fThread = spawn_kernel_thread(&Server::_ListenerThreadStart, + "NFSv4 Listener", B_NORMAL_PRIORITY, this); + if (fThread < B_OK) + return fThread; + + status_t result = resume_thread(fThread); + if (result != B_OK) { + kill_thread(fThread); + return result; + } + + return B_OK; +} + + +status_t +Server::SendCall(Call* call, Reply** reply) +{ + status_t result; + + Request* req = new(std::nothrow) Request; + if (req == NULL) + return B_NO_MEMORY; + + uint32 xid = _GetXID(); + call->SetXID(xid); + req->fXID = xid; + req->fReply = reply; + req->fNext = NULL; + + fRequests.AddRequest(req); + + XDR::WriteStream& stream = call->Stream(); + result = fConnection->Send(stream.Buffer(), stream.Size()); + if (result != B_OK) + goto out_cancel; + + result = req->fEvent.Wait(B_RELATIVE_TIMEOUT, kWaitTime); + if (result != B_OK) + goto out_cancel; + + delete req; + return B_OK; + +out_cancel: + CancelCall(xid); + delete req; + return result; +} + + +void +Server::CancelCall(uint32 xid) +{ + fRequests.FindRequest(xid); +} + + +uint32 +Server::_GetXID() +{ + return (uint32)atomic_add(&fXID, 1); +} + + +status_t +Server::_Listener() +{ + status_t result; + uint32 size; + void* buffer; + + while (!fThreadCancel) { + result = fConnection->Receive(&buffer, &size); + if (result != B_OK) + return result; + + Reply* reply = new(std::nothrow) Reply(buffer, size); + if (reply == NULL) { + free(buffer); + return B_NO_MEMORY; + } + + Request* req = fRequests.FindRequest(reply->GetXID()); + if (req != NULL) { + *req->fReply = reply; + req->fEvent.NotifyAll(); + } + } + + return B_OK; +} + + +status_t +Server::_ListenerThreadStart(void* ptr) +{ + Server* server = reinterpret_cast(ptr); + return server->_Listener(); +} + + +ServerManager::ServerManager() + : + fRoot(NULL) +{ + mutex_init(&fLock, NULL); +} + + +ServerManager::~ServerManager() +{ +} + + +status_t +ServerManager::Acquire(Server** pserv, uint32 ip, uint16 port, Transport proto) +{ + status_t result; + + ServerAddress id; + id.fAddress = ip; + id.fPort = port; + id.fProtocol = proto; + + mutex_lock(&fLock); + ServerNode* node = _Find(id); + if (node != NULL) { + node->fRefCount++; + mutex_unlock(&fLock); + + *pserv = node->fServer; + return B_OK; + } + mutex_unlock(&fLock); + dprintf("creating\n"); + + node = new(std::nothrow) ServerNode; + if (node == NULL) + return B_NO_MEMORY; + + node->fID = id; + + Connection* conn; + result = Connection::Connect(&conn, id); + if (result != B_OK) { + delete node; + return result; + } + + node->fServer = new Server(conn); + if (node->fServer == NULL) { + delete node; + delete conn; + return B_NO_MEMORY; + } + + node->fRefCount = 1; + node->fLeft = node->fRight = NULL; + + // We need to be prepared if someone already connected to the server and + // updated the BST. In such case we use that connection and cancel ours. + mutex_lock(&fLock); + ServerNode* nd = _Insert(node); + if (nd != node) { + nd->fRefCount++; + mutex_unlock(&fLock); + + delete node->fServer; + delete node; + *pserv = nd->fServer; + return B_OK; + } + mutex_unlock(&fLock); + + *pserv = node->fServer; + return B_OK; +} + + +void +ServerManager::Release(Server* serv) +{ +#if 0 + mutex_lock(&fLock); + ServerNode* node = _Find(serv->GetID()); + if (node != NULL) { + node->fRefCount--; + + if (node->fRefCount == 0) + _Delete(node); + } + mutex_unlock(&fLock); + + if (node != NULL) { + delete node->fServer; + delete node; + } +#endif +} + + +ServerNode* +ServerManager::_Find(ServerAddress& id) +{ + ServerNode* node = fRoot; + while (node != NULL) { + dprintf("passing addr: %x port %d proto: %d\n", (int)node->fID.fAddress, (int)node->fID.fPort, (int)node->fID.fProtocol); + if (node->fID == id) + return node; + if (node->fID < id) + node = node->fRight; + else + node = node->fLeft; + } + + return node; +} + + +ServerNode* +ServerManager::_Insert(ServerNode* node) +{ + ServerNode* previous = NULL; + ServerNode* current = fRoot; + while (current != NULL) { + if (current->fID == node->fID) + return current; + if (current->fID < node->fID) { + previous = current; + current = current->fRight; + } else { + previous = current; + current = current->fLeft; + } + } + + if (previous == NULL) + fRoot = node; + else if (previous->fID < node->fID) + previous->fRight = node; + else + previous->fLeft = node; + + return node; +} + diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCServer.h b/src/add-ons/kernel/file_systems/nfs4/RPCServer.h new file mode 100644 index 0000000000..3c03cf02db --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/RPCServer.h @@ -0,0 +1,104 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ +#ifndef RPCSERVER_H +#define RPCSERVER_H + + +#include +#include + +#include "Connection.h" +#include "RPCCall.h" +#include "RPCReply.h" + + +namespace RPC { + +struct Request { + uint32 fXID; + ConditionVariable fEvent; + Reply** fReply; + + Request* fNext; +}; + +class RequestManager { +public: + RequestManager(); + ~RequestManager(); + + void AddRequest(Request* req); + Request* FindRequest(uint32 xid); + +private: + mutex fLock; + Request* fQueueHead; + Request* fQueueTail; + +}; + +class Server { +public: + Server(Connection* conn); + virtual ~Server(); + + status_t SendCall(Call* call, Reply** reply); + inline void CancelCall(uint32 xid); + +protected: + inline uint32 _GetXID(); + status_t _StartListening(); + +private: + status_t _Listener(); + static status_t _ListenerThreadStart(void* ptr); + + thread_id fThread; + bool fThreadCancel; + + RequestManager fRequests; + Connection* fConnection; + + vint32 fXID; + static const bigtime_t kWaitTime = 1000000; +}; + +struct ServerNode { + ServerAddress fID; + Server* fServer; + int fRefCount; + + ServerNode* fLeft; + ServerNode* fRight; +}; + +class ServerManager { +public: + ServerManager(); + ~ServerManager(); + + status_t Acquire(Server** pserv, uint32 ip, uint16 port, + Transport proto); + void Release(Server* serv); + +private: + + + ServerNode* _Find(ServerAddress& id); + void _Delete(ServerNode* node); + ServerNode* _Insert(ServerNode* node); + + ServerNode* fRoot; + mutex fLock; +}; + +} // namespace RPC + + +#endif // RPCSERVER_H + From 5cdf02db0920d413ae243d57dbf4bd5070b8f2fb Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Sat, 26 May 2012 18:38:51 +0200 Subject: [PATCH 009/252] nfs4: Add RPC::Server release and repair code --- .../kernel/file_systems/nfs4/RPCServer.cpp | 100 +++++++++++++++--- .../kernel/file_systems/nfs4/RPCServer.h | 53 ++++++---- 2 files changed, 116 insertions(+), 37 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp b/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp index 031f0051cc..f5fa966d54 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp @@ -60,7 +60,6 @@ RequestManager::FindRequest(uint32 xid) if (fQueueHead == req) fQueueHead = req->fNext; mutex_unlock(&fLock); - dprintf("Found %x %x\n", (unsigned int)fQueueHead, (unsigned int)fQueueTail); return req; } @@ -68,16 +67,16 @@ RequestManager::FindRequest(uint32 xid) prev = req; req = req->fNext; } - dprintf("Nothing found\n"); mutex_unlock(&fLock); return NULL; } -Server::Server(Connection* conn) +Server::Server(Connection* conn, ServerAddress* addr) : fConnection(conn), + fAddress(addr), fXID(rand() << 1) { _StartListening(); @@ -98,8 +97,8 @@ Server::~Server() status_t Server::_StartListening() { - dprintf("new thread\n"); fThreadCancel = false; + fThreadError = B_OK; fThread = spawn_kernel_thread(&Server::_ListenerThreadStart, "NFSv4 Listener", B_NORMAL_PRIORITY, this); if (fThread < B_OK) @@ -120,6 +119,9 @@ Server::SendCall(Call* call, Reply** reply) { status_t result; + if (fThreadError != B_OK) + return fThreadError; + Request* req = new(std::nothrow) Request; if (req == NULL) return B_NO_MEMORY; @@ -145,16 +147,21 @@ Server::SendCall(Call* call, Reply** reply) return B_OK; out_cancel: - CancelCall(xid); + fRequests.FindRequest(xid); delete req; return result; } -void -Server::CancelCall(uint32 xid) +status_t +Server::Repair() { - fRequests.FindRequest(xid); + fThreadCancel = true; + status_t result = fConnection->Reconnect(); + if (result != B_OK) + return result; + wait_for_thread(fThread, &result); + return _StartListening(); } @@ -174,12 +181,15 @@ Server::_Listener() while (!fThreadCancel) { result = fConnection->Receive(&buffer, &size); - if (result != B_OK) + if (result != B_OK) { + fThreadError = result; return result; + } Reply* reply = new(std::nothrow) Reply(buffer, size); if (reply == NULL) { free(buffer); + fThreadError = result; return B_NO_MEMORY; } @@ -212,6 +222,7 @@ ServerManager::ServerManager() ServerManager::~ServerManager() { + mutex_destroy(&fLock); } @@ -235,7 +246,6 @@ ServerManager::Acquire(Server** pserv, uint32 ip, uint16 port, Transport proto) return B_OK; } mutex_unlock(&fLock); - dprintf("creating\n"); node = new(std::nothrow) ServerNode; if (node == NULL) @@ -250,7 +260,7 @@ ServerManager::Acquire(Server** pserv, uint32 ip, uint16 port, Transport proto) return result; } - node->fServer = new Server(conn); + node->fServer = new Server(conn, &node->fID); if (node->fServer == NULL) { delete node; delete conn; @@ -283,9 +293,8 @@ ServerManager::Acquire(Server** pserv, uint32 ip, uint16 port, Transport proto) void ServerManager::Release(Server* serv) { -#if 0 mutex_lock(&fLock); - ServerNode* node = _Find(serv->GetID()); + ServerNode* node = _Find(serv->ID()); if (node != NULL) { node->fRefCount--; @@ -298,16 +307,14 @@ ServerManager::Release(Server* serv) delete node->fServer; delete node; } -#endif } ServerNode* -ServerManager::_Find(ServerAddress& id) +ServerManager::_Find(const ServerAddress& id) { ServerNode* node = fRoot; while (node != NULL) { - dprintf("passing addr: %x port %d proto: %d\n", (int)node->fID.fAddress, (int)node->fID.fPort, (int)node->fID.fProtocol); if (node->fID == id) return node; if (node->fID < id) @@ -320,6 +327,67 @@ ServerManager::_Find(ServerAddress& id) } +void +ServerManager::_Delete(ServerNode* node) +{ + bool found = false; + ServerNode* previous = NULL; + ServerNode* current = fRoot; + while (current != NULL) { + if (current->fID == node->fID) { + found = true; + break; + } + + if (current->fID < node->fID) { + previous = current; + current = current->fRight; + } else { + previous = current; + current = current->fLeft; + } + } + + if (!found) + return; + + if (previous == NULL) + fRoot = NULL; + else if (current->fLeft == NULL && current->fRight == NULL) { + if (previous->fID < node->fID) + previous->fRight = NULL; + else + previous->fLeft = NULL; + } else if (current->fLeft != NULL && current->fRight == NULL) { + if (previous->fID < node->fID) + previous->fRight = current->fLeft; + else + previous->fLeft = current->fLeft; + } else if (current->fLeft == NULL && current->fRight != NULL) { + if (previous->fID < node->fID) + previous->fRight = current->fRight; + else + previous->fLeft = current->fRight; + } else { + ServerNode* left_prev = current; + ServerNode* left = current->fLeft; + + while (left->fLeft != NULL) { + left_prev = left; + left = left->fLeft; + } + + if (previous->fID < node->fID) + previous->fRight = left; + else + previous->fLeft = left; + + + left_prev->fLeft = NULL; + } +} + + ServerNode* ServerManager::_Insert(ServerNode* node) { diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCServer.h b/src/add-ons/kernel/file_systems/nfs4/RPCServer.h index 3c03cf02db..5a7d3d0a46 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RPCServer.h +++ b/src/add-ons/kernel/file_systems/nfs4/RPCServer.h @@ -44,37 +44,49 @@ private: class Server { public: - Server(Connection* conn); - virtual ~Server(); + Server(Connection* conn, + ServerAddress* addr); + virtual ~Server(); - status_t SendCall(Call* call, Reply** reply); - inline void CancelCall(uint32 xid); + status_t SendCall(Call* call, Reply** reply); -protected: - inline uint32 _GetXID(); - status_t _StartListening(); + status_t Repair(); + + inline const ServerAddress& ID() const; private: - status_t _Listener(); - static status_t _ListenerThreadStart(void* ptr); + inline uint32 _GetXID(); - thread_id fThread; - bool fThreadCancel; + status_t _StartListening(); - RequestManager fRequests; - Connection* fConnection; + status_t _Listener(); + static status_t _ListenerThreadStart(void* ptr); - vint32 fXID; - static const bigtime_t kWaitTime = 1000000; + thread_id fThread; + bool fThreadCancel; + status_t fThreadError; + + RequestManager fRequests; + Connection* fConnection; + const ServerAddress* fAddress; + + vint32 fXID; + static const bigtime_t kWaitTime = 1000000; }; +inline const ServerAddress& +Server::ID() const +{ + return *fAddress; +} + struct ServerNode { ServerAddress fID; - Server* fServer; - int fRefCount; + Server* fServer; + int fRefCount; - ServerNode* fLeft; - ServerNode* fRight; + ServerNode* fLeft; + ServerNode* fRight; }; class ServerManager { @@ -88,8 +100,7 @@ public: private: - - ServerNode* _Find(ServerAddress& id); + ServerNode* _Find(const ServerAddress& id); void _Delete(ServerNode* node); ServerNode* _Insert(ServerNode* node); From b82f4c07eba5dd04d1e2878ea79f47183d83c707 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Sat, 26 May 2012 19:02:20 +0200 Subject: [PATCH 010/252] nfs4: Make RPC::Reply decode RPC errors --- .../kernel/file_systems/nfs4/RPCReply.cpp | 65 +++++++++++++++++-- 1 file changed, 59 insertions(+), 6 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCReply.cpp b/src/add-ons/kernel/file_systems/nfs4/RPCReply.cpp index b09728a4e3..3dfa899069 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RPCReply.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RPCReply.cpp @@ -14,6 +14,29 @@ using namespace RPC; +enum { + REPLY = 1 +}; + +enum { + MSG_ACCEPTED = 0, + MSG_DENIED = 1 +}; + +enum accept_stat { + SUCCESS = 0, /* RPC executed successfully */ + PROG_UNAVAIL = 1, /* remote hasn't exported program */ + PROG_MISMATCH = 2, /* remote can't support version # */ + PROC_UNAVAIL = 3, /* program can't support procedure */ + GARBAGE_ARGS = 4, /* procedure can't decode params */ + SYSTEM_ERR = 5 /* e.g. memory allocation failure */ +}; + +enum reject_stat { + RPC_MISMATCH = 0, /* RPC version number != 2 */ + AUTH_ERROR = 1 /* remote can't authenticate caller */ +}; + Reply::Reply(void *buffer, int size) : @@ -22,12 +45,42 @@ Reply::Reply(void *buffer, int size) fBuffer(buffer) { fXID = fStream.GetUInt(); -#if 0 - int32 type = fStream.GetInt(); - int32 state = fStream.GetInt(); - int32 auth = fStream.GetInt(); - fStream.GetOpaque(NULL); -#endif + if (fStream.GetInt() != REPLY) { + fError = B_BAD_VALUE; + return; + } + + if (fStream.GetInt() == MSG_ACCEPTED) { + fStream.GetInt(); + fStream.GetOpaque(NULL); + + switch (fStream.GetInt()) { + case SUCCESS: + return; + case PROG_UNAVAIL: + case PROG_MISMATCH: + case PROC_UNAVAIL: + fError = B_DEVICE_NOT_FOUND; + return; + case GARBAGE_ARGS: + fError = B_MISMATCHED_VALUES; + return; + case SYSTEM_ERR: + fError = B_ERROR; + return; + default: + fError = B_BAD_VALUE; + return; + } + } else { // MSG_DENIED + if (fStream.GetInt() == RPC_MISMATCH) { + fError = B_DEVICE_NOT_FOUND; + return; + } else { // AUTH_ERROR + fError = B_PERMISSION_DENIED; + return; + } + } } From 3e945c7ff0912e7d81874165457eba126d0d673e Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Sat, 26 May 2012 19:16:31 +0200 Subject: [PATCH 011/252] nfs4: Make mount() send null nfs4 call --- .../file_systems/nfs4/kernel_interface.cpp | 66 +++++++++++++++---- 1 file changed, 52 insertions(+), 14 deletions(-) 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 391678b406..111a2ddad2 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -10,6 +10,11 @@ #include #include "Connection.h" +#include "RPCServer.h" + + +#define NFS_PROC_NULL 0 +#define NFS_PROC_COMPOUND 1 extern fs_volume_ops gNFSv4VolumeOps; @@ -19,12 +24,27 @@ extern "C" void dprintf(const char* format, ...); +RPC::ServerManager* gRPCServerManager; + + static status_t nfs4_mount(fs_volume* volume, const char* device, uint32 flags, const char* args, ino_t* _rootVnodeID) { dprintf("NFS4 Mounting...\n"); + RPC::Server *s; + // hardcoded ip 192.168.1.70 + gRPCServerManager->Acquire(&s, 0xc0a80146, 2049, ProtocolTCP); + + RPC::Reply *r; + RPC::Call *c = RPC::Call::Create(NFS_PROC_NULL, RPC::Auth::CreateSys(), + RPC::Auth::CreateNone()); + s->SendCall(c, &r); + delete r; + delete c; + gRPCServerManager->Release(s); + volume->ops = &gNFSv4VolumeOps; status_t error = publish_vnode(volume, 0, (void*)0xdeadbeef, @@ -55,26 +75,44 @@ nfs4_put_vnode(fs_volume* volume, fs_vnode* vnode, bool reenter) } +status_t +nfs4_init() +{ + dprintf("NFS4 Init\n"); + + status_t result = Connection::Init(); + if (result != B_OK) + return result; + + gRPCServerManager = new(std::nothrow) RPC::ServerManager; + if (gRPCServerManager == NULL) + return B_NO_MEMORY; + return B_OK; +} + + +status_t +nfs4_uninit() +{ + dprintf("NFS4 Uninit\n"); + + delete gRPCServerManager; + + status_t result = Connection::CleanUp(); + if (result != B_OK) + return result; + return B_OK; +} + + static status_t nfs4_std_ops(int32 op, ...) { - status_t result; - switch (op) { case B_MODULE_INIT: - dprintf("NFS4 Init\n"); - result = Connection::Init(); - if (result != B_OK) - return result; - return B_OK; - + return nfs4_init(); case B_MODULE_UNINIT: - dprintf("NFS4 Uninit\n"); - result = Connection::CleanUp(); - if (result != B_OK) - return result; - return B_OK; - + return nfs4_uninit(); default: return B_ERROR; } From 4aeb59520783ebf73e2c9eb93cbc0677177b4cb5 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Tue, 29 May 2012 23:33:07 +0200 Subject: [PATCH 012/252] nfs4: Add some NFS4 constants --- .../kernel/file_systems/nfs4/NFS4Defs.h | 122 ++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100644 src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h new file mode 100644 index 0000000000..7208d6f4f5 --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h @@ -0,0 +1,122 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ +#ifndef NFS4DEFS_H +#define NFS4DEFS_H + + +enum Procedure { + ProcNull = 0, + ProcCompound = 1 +}; + +enum Opcode { + OpAccess = 3, + OpGetAttr = 9, + OpGetFH = 10, + OpLookUp = 15, + OpPutRootFH = 24 +}; + +enum Access { + ACCESS4_READ = 0x00000001, + ACCESS4_LOOKUP = 0x00000002, + ACCESS4_MODIFY = 0x00000004, + ACCESS4_EXTEND = 0x00000008, + ACCESS4_DELETE = 0x00000010, + ACCESS4_EXECUTE = 0x00000020 +}; + +enum Attribute { + // Mandatory Attributes + FATTR4_SUPPORTED_ATTRS = 0, + FATTR4_TYPE = 1, + FATTR4_FH_EXPIRE_TYPE = 2, + FATTR4_CHANGE = 3, + FATTR4_SIZE = 4, + FATTR4_LINK_SUPPORT = 5, + FATTR4_SYMLINK_SUPPORT = 6, + FATTR4_NAMED_ATTR = 7, + FATTR4_FSID = 8, + FATTR4_UNIQUE_HANDLES = 9, + FATTR4_LEASE_TIME = 10, + FATTR4_RDATTR_ERROR = 11, + FATTR4_FILEHANDLE = 19, + + // Recommended Attributes + FATTR4_ACL = 12, + FATTR4_ACLSUPPORT = 13, + FATTR4_ARCHIVE = 14, + FATTR4_CANSETTIME = 15, + FATTR4_CASE_INSENSITIVE = 16, + FATTR4_CASE_PRESERVING = 17, + FATTR4_CHOWN_RESTRICTED = 18, + FATTR4_FILEID = 20, + FATTR4_FILES_AVAIL = 21, + FATTR4_FILES_FREE = 22, + FATTR4_FILES_TOTAL = 23, + FATTR4_FS_LOCATIONS = 24, + FATTR4_HIDDEN = 25, + FATTR4_HOMOGENEOUS = 26, + FATTR4_MAXFILESIZE = 27, + FATTR4_MAXLINK = 28, + FATTR4_MAXNAME = 29, + FATTR4_MAXREAD = 30, + FATTR4_MAXWRITE = 31, + FATTR4_MIMETYPE = 32, + FATTR4_MODE = 33, + FATTR4_NO_TRUNC = 34, + FATTR4_NUMLINKS = 35, + FATTR4_OWNER = 36, + FATTR4_OWNER_GROUP = 37, + FATTR4_QUOTA_AVAIL_HARD = 38, + FATTR4_QUOTA_AVAIL_SOFT = 39, + FATTR4_QUOTA_USED = 40, + FATTR4_RAWDEV = 41, + FATTR4_SPACE_AVAIL = 42, + FATTR4_SPACE_FREE = 43, + FATTR4_SPACE_TOTAL = 44, + FATTR4_SPACE_USED = 45, + FATTR4_SYSTEM = 46, + FATTR4_TIME_ACCESS = 47, + FATTR4_TIME_ACCESS_SET = 48, + FATTR4_TIME_BACKUP = 49, + FATTR4_TIME_CREATE = 50, + FATTR4_TIME_DELTA = 51, + FATTR4_TIME_METADATA = 52, + FATTR4_TIME_MODIFY = 53, + FATTR4_TIME_MODIFY_SET = 54, + FATTR4_MOUNTED_ON_FILEID = 55 +}; + +enum FileHandleExpiryType { + FH4_PERSISTENT = 0x00, + FH4_NOEXPIRE_WITH_OPEN = 0x01, + FH4_VOLATILE_ANY = 0x02, + FH4_VOL_MIGRATION = 0x04, + FH4_VOL_RENAME = 0x08 +}; + +enum Errors { + NFS4_OK = 0, + NFS4ERR_PERM = 1, + NFS4ERR_NOENT = 2, + NFS4ERR_IO = 5, + NFS4ERR_NXIO = 6, + NFS4ERR_ACCESS = 13, + NFS4ERR_EXIST = 17, + NFS4ERR_XDEV = 18, + NFS4ERR_NOTDIR = 20, + NFS4ERR_ISDIR = 21, + NFS4ERR_INVAL = 22, + NFS4ERR_FBIG = 27 + //... +}; + + +#endif // NFS4DEFS_H + From d08c284cec641c1aa88bc61985852989a6069a3f Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Tue, 29 May 2012 23:39:56 +0200 Subject: [PATCH 013/252] nfs4: Add NFS4 request builder Currently supports only the following operations: ACCESS, GETATTR, GETFH LOOKUP and PUTROOTFH. --- src/add-ons/kernel/file_systems/nfs4/Jamfile | 1 + .../file_systems/nfs4/RequestBuilder.cpp | 143 ++++++++++++++++++ .../kernel/file_systems/nfs4/RequestBuilder.h | 43 ++++++ 3 files changed, 187 insertions(+) create mode 100644 src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp create mode 100644 src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h diff --git a/src/add-ons/kernel/file_systems/nfs4/Jamfile b/src/add-ons/kernel/file_systems/nfs4/Jamfile index db1386b800..8c82e50edd 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Jamfile +++ b/src/add-ons/kernel/file_systems/nfs4/Jamfile @@ -5,6 +5,7 @@ UsePrivateHeaders kernel ; KernelAddon nfs4 : Connection.cpp kernel_interface.cpp + RequestBuilder.cpp RPCAuth.cpp RPCCall.cpp RPCReply.cpp diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp new file mode 100644 index 0000000000..3b53a4090c --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp @@ -0,0 +1,143 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ + + +#include "RequestBuilder.h" + +#include + + +RequestBuilder::RequestBuilder(Procedure proc) + : + fOpCount(0), + fProcedure(proc), + fRequest(RPC::Call::Create(proc, RPC::Auth::CreateSys(), + RPC::Auth::CreateNone())) +{ + if (fProcedure == ProcCompound) { + fRequest->Stream().AddOpaque(NULL, 0); + fRequest->Stream().AddUInt(0); + + fOpCountPosition = fRequest->Stream().Current(); + fRequest->Stream().AddUInt(0); + } +} + + +RequestBuilder::~RequestBuilder() +{ + delete fRequest; +} + + +status_t +RequestBuilder::Access() +{ + if (fProcedure != ProcCompound) + return B_BAD_VALUE; + if (fRequest == NULL) + return B_NO_MEMORY; + + fRequest->Stream().AddUInt(OpAccess); + fRequest->Stream().AddUInt(ACCESS4_READ | ACCESS4_LOOKUP | ACCESS4_MODIFY + | ACCESS4_EXTEND | ACCESS4_DELETE + | ACCESS4_EXECUTE); + fOpCount++; + + return B_OK; +} + + +status_t +RequestBuilder::GetAttr(Attribute* attrs, uint32 count) +{ + if (fProcedure != ProcCompound) + return B_BAD_VALUE; + if (fRequest == NULL) + return B_NO_MEMORY; + + fRequest->Stream().AddUInt(OpGetAttr); + + // 2 is safe in NFS4, not in NFS4.1 though + uint32 bitmap[2]; + memset(bitmap, 0, sizeof(bitmap)); + for (uint32 i = 0; i < count; i++) { + bitmap[(int)attrs[i] / 32] |= 1 << (int)attrs[i] % 32; + } + + uint32 bcount = bitmap[1] != 0 ? 2 : 1; + fRequest->Stream().AddUInt(bcount); + for (uint32 i = 0; i < bcount; i++) + fRequest->Stream().AddUInt(bitmap[i]); + + fOpCount++; + + return B_OK; +} + + +status_t +RequestBuilder::GetFH() +{ + if (fProcedure != ProcCompound) + return B_BAD_VALUE; + if (fRequest == NULL) + return B_NO_MEMORY; + + fRequest->Stream().AddUInt(OpGetFH); + fOpCount++; + + return B_OK; +} + + +status_t +RequestBuilder::LookUp(const char* name) +{ + if (fProcedure != ProcCompound) + return B_BAD_VALUE; + if (fRequest == NULL) + return B_NO_MEMORY; + if (name == NULL) + return B_BAD_VALUE; + + fRequest->Stream().AddUInt(OpLookUp); + fRequest->Stream().AddString(name, strlen(name)); + fOpCount++; + + return B_OK; +} + + +status_t +RequestBuilder::PutRootFH() +{ + if (fProcedure != ProcCompound) + return B_BAD_VALUE; + if (fRequest == NULL) + return B_NO_MEMORY; + + fRequest->Stream().AddUInt(OpPutRootFH); + fOpCount++; + + return B_OK; +} + + +RPC::Call* +RequestBuilder::Request() +{ + if (fProcedure == ProcCompound) + fRequest->Stream().InsertUInt(fOpCountPosition, fOpCount); + + if (fRequest == NULL || fRequest->Stream().Error() == B_OK) + return fRequest; + else + return NULL; +} + diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h new file mode 100644 index 0000000000..377519f15c --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h @@ -0,0 +1,43 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ +#ifndef REQUESTBUILDER_H +#define REQUESTBUILDER_H + + +#include + +#include "NFS4Defs.h" +#include "RPCCall.h" +#include "XDR.h" + + +class RequestBuilder { +public: + RequestBuilder(Procedure proc); + ~RequestBuilder(); + + status_t Access(); + status_t GetAttr(Attribute* attrs, uint32 count); + status_t GetFH(); + status_t LookUp(const char* name); + status_t PutRootFH(); + + RPC::Call* Request(); + +private: + uint32 fOpCount; + XDR::Stream::Position fOpCountPosition; + + Procedure fProcedure; + + RPC::Call* fRequest; +}; + + +#endif // REQUESTBUILDER_H + From 196403c9abaa7976cc2af2267230208533b5fe61 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Tue, 29 May 2012 23:56:19 +0200 Subject: [PATCH 014/252] nfs4: Add NFS4 reply interpreter Currently supported operations are: ACCESS, GETATTR (partially), GETFH, LOOKUP and PUTROOTFH. --- src/add-ons/kernel/file_systems/nfs4/Jamfile | 1 + .../kernel/file_systems/nfs4/NFS4Defs.h | 7 + .../file_systems/nfs4/ReplyInterpreter.cpp | 181 ++++++++++++++++++ .../file_systems/nfs4/ReplyInterpreter.h | 62 ++++++ 4 files changed, 251 insertions(+) create mode 100644 src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp create mode 100644 src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h diff --git a/src/add-ons/kernel/file_systems/nfs4/Jamfile b/src/add-ons/kernel/file_systems/nfs4/Jamfile index 8c82e50edd..e58c558db9 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Jamfile +++ b/src/add-ons/kernel/file_systems/nfs4/Jamfile @@ -5,6 +5,7 @@ UsePrivateHeaders kernel ; KernelAddon nfs4 : Connection.cpp kernel_interface.cpp + ReplyInterpreter.cpp RequestBuilder.cpp RPCAuth.cpp RPCCall.cpp diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h index 7208d6f4f5..2762d5f114 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h @@ -9,6 +9,13 @@ #define NFS4DEFS_H +#define NFS4_FHSIZE 128 + +struct Filehandle { + uint8 fSize; + uint8 fFH[NFS4_FHSIZE]; +}; + enum Procedure { ProcNull = 0, ProcCompound = 1 diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp new file mode 100644 index 0000000000..4ff308137d --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp @@ -0,0 +1,181 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ + + +#include "ReplyInterpreter.h" + +#include + +#include + + +ReplyInterpreter::ReplyInterpreter(RPC::Reply* reply) + : + fReply(reply) +{ + fReply->Stream().GetUInt(); + fReply->Stream().GetOpaque(NULL); + fReply->Stream().GetUInt(); +} + + +ReplyInterpreter::~ReplyInterpreter() +{ + delete fReply; +} + + +status_t +ReplyInterpreter::Access(uint32* supported, uint32* allowed) +{ + status_t res = _OperationError(OpAccess); + if (res != B_OK) + return res; + + uint32 support = fReply->Stream().GetUInt(); + uint32 allow = fReply->Stream().GetUInt(); + + if (supported != NULL) + *supported = support; + if (allowed != NULL) + *allowed = allow; + + return B_OK; +} + + +// Bit Twiddling Hacks +// http://graphics.stanford.edu/~seander/bithacks.html +static inline uint32 sCountBits(uint32 v) +{ + v = v - ((v >> 1) & 0x55555555); + v = (v & 0x33333333) + ((v >> 2) & 0x33333333); + return ((v + (v >> 4) & 0xF0F0F0F) * 0x1010101) >> 24; +} + + +static inline bool sIsAttrSet(Attribute attr, uint32* bitmap, uint32 count) +{ + if ((uint32)attr / 32 >= count) + return false; + + return (bitmap[attr / 32] & 1 << attr % 32) != 0; +} + + +status_t +ReplyInterpreter::GetAttr(AttrValue** attrs, uint32* count) +{ + status_t res = _OperationError(OpGetAttr); + if (res != B_OK) + return res; + + uint32 bcount = fReply->Stream().GetUInt(); + uint32 *bitmap = new(std::nothrow) uint32[bcount]; + if (bitmap == NULL) + return B_NO_MEMORY; + + uint32 attr_count = 0; + for (uint32 i = 0; i < bcount; i++) { + bitmap[i] = fReply->Stream().GetUInt(); + attr_count = sCountBits(bitmap[i]); + } + + uint32 size; + const void* ptr = fReply->Stream().GetOpaque(&size); + XDR::ReadStream stream(const_cast(ptr), size); + + AttrValue* values = new(std::nothrow) AttrValue[attr_count]; + if (values == NULL) { + delete bitmap; + return B_NO_MEMORY; + } + + uint32 current = 0; + + if (sIsAttrSet(FATTR4_TYPE, bitmap, bcount)) { + values[current].fAttribute = FATTR4_TYPE; + values[current].fData.fValue32 = stream.GetInt(); + current++; + } + + if (sIsAttrSet(FATTR4_FH_EXPIRE_TYPE, bitmap, bcount)) { + values[current].fAttribute = FATTR4_FH_EXPIRE_TYPE; + values[current].fData.fValue32 = stream.GetUInt(); + current++; + } + + if (sIsAttrSet(FATTR4_FILEID, bitmap, bcount)) { + values[current].fAttribute = FATTR4_FILEID; + values[current].fData.fValue64 = stream.GetUHyper(); + current++; + } + + delete bitmap; + + *count = attr_count; + *attrs = values; + return B_OK; +} + + +status_t +ReplyInterpreter::GetFH(Filehandle* fh) +{ + status_t res = _OperationError(OpGetFH); + if (res != B_OK) + return res; + + uint32 size; + const void* ptr = fReply->Stream().GetOpaque(&size); + if (ptr == NULL || size > NFS4_FHSIZE) + return B_BAD_VALUE; + + if (fh != NULL) { + fh->fSize = size; + memcpy(fh->fFH, ptr, size); + } + + return B_OK; +} + + +status_t +ReplyInterpreter::_OperationError(Opcode op) +{ + if (fReply->Error() != B_OK || fReply->Stream().IsEOF()) + return fReply->Error(); + + if (fReply->Stream().GetInt() != op) + return B_BAD_VALUE; + + return _NFS4ErrorToHaiku(fReply->Stream().GetUInt()); +} + + +status_t +ReplyInterpreter::_NFS4ErrorToHaiku(uint32 x) +{ + switch (x) { + case NFS4_OK: return B_OK; + case NFS4ERR_PERM: return B_PERMISSION_DENIED; + case NFS4ERR_NOENT: return B_ENTRY_NOT_FOUND; + case NFS4ERR_IO: return B_IO_ERROR; + case NFS4ERR_NXIO: return B_DEVICE_NOT_FOUND; + case NFS4ERR_ACCESS: return B_PERMISSION_DENIED; + case NFS4ERR_EXIST: return B_FILE_EXISTS; + case NFS4ERR_XDEV: return B_CROSS_DEVICE_LINK; + case NFS4ERR_NOTDIR: return B_NOT_A_DIRECTORY; + case NFS4ERR_ISDIR: return B_IS_A_DIRECTORY; + case NFS4ERR_INVAL: return B_BAD_VALUE; + case NFS4ERR_FBIG: return B_FILE_TOO_LARGE; + // ... + default: return B_ERROR; + } +} + diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h new file mode 100644 index 0000000000..83973b17dd --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h @@ -0,0 +1,62 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ +#ifndef REPLYINTERPRETER_H +#define REPLYINTERPRETER_H + + +#include + +#include "NFS4Defs.h" +#include "RPCReply.h" + + +struct AttrValue { + uint8 fAttribute; + union { + uint32 fValue32; + uint64 fValue64; + void* fPointer; + } fData; +}; + +class ReplyInterpreter { +public: + ReplyInterpreter(RPC::Reply* reply); + ~ReplyInterpreter(); + + status_t Access(uint32* supported, uint32* allowed); + status_t GetAttr(AttrValue** attrs, uint32* count); + status_t GetFH(Filehandle* fh); + inline status_t LookUp(); + inline status_t PutRootFH(); + +private: + status_t _OperationError(Opcode op); + + static status_t _NFS4ErrorToHaiku(uint32 x); + + RPC::Reply* fReply; +}; + + +inline status_t +ReplyInterpreter::LookUp() +{ + return _OperationError(OpLookUp); +} + + +inline status_t +ReplyInterpreter::PutRootFH() +{ + return _OperationError(OpPutRootFH); +} + + +#endif // REPLYINTERPRETER_H + From 7fdee1565d16d89ef406a835b5b7cb2b85240eca Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Tue, 29 May 2012 23:58:14 +0200 Subject: [PATCH 015/252] nfs4: No need to cast from enum to int --- src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp index 3b53a4090c..341d54385a 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp @@ -67,7 +67,7 @@ RequestBuilder::GetAttr(Attribute* attrs, uint32 count) uint32 bitmap[2]; memset(bitmap, 0, sizeof(bitmap)); for (uint32 i = 0; i < count; i++) { - bitmap[(int)attrs[i] / 32] |= 1 << (int)attrs[i] % 32; + bitmap[attrs[i] / 32] |= 1 << attrs[i] % 32; } uint32 bcount = bitmap[1] != 0 ? 2 : 1; From e552920f09647d2e8a0743dceac5a37f1d57c5be Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Wed, 30 May 2012 22:09:31 +0200 Subject: [PATCH 016/252] nfs4: Fix rpc listener thread cancelation recv on UDP sockets is not interrupted when the socket is closed. Additionaly, signals do not interrupt kernel threads, that is why new function interrupt_thread was implemented in order to cancel listener thread. --- headers/os/drivers/KernelExport.h | 1 + .../kernel/file_systems/nfs4/Connection.cpp | 15 ++++++++++++++- src/add-ons/kernel/file_systems/nfs4/Connection.h | 1 + .../kernel/file_systems/nfs4/RPCServer.cpp | 8 +++++++- src/system/kernel/thread.cpp | 14 ++++++++++++++ 5 files changed, 37 insertions(+), 2 deletions(-) diff --git a/headers/os/drivers/KernelExport.h b/headers/os/drivers/KernelExport.h index 3e2e5848dd..14c707dc66 100644 --- a/headers/os/drivers/KernelExport.h +++ b/headers/os/drivers/KernelExport.h @@ -138,6 +138,7 @@ extern bool cancel_timer(timer *t); /* kernel threads */ extern thread_id spawn_kernel_thread(thread_func function, const char *name, int32 priority, void *arg); +extern status_t interrupt_thread(thread_id id); /* signal functions */ extern int send_signal_etc(pid_t thread, uint signal, uint32 flags); diff --git a/src/add-ons/kernel/file_systems/nfs4/Connection.cpp b/src/add-ons/kernel/file_systems/nfs4/Connection.cpp index 094dfe6da3..c1b7e89f75 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Connection.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Connection.cpp @@ -55,7 +55,8 @@ Connection::Connection(const sockaddr_in& addr, Transport proto, bool markers) Connection::~Connection() { - kclosesocket(fSock); + if (fSock != -1) + kclosesocket(fSock); mutex_destroy(&fSockLock); } @@ -184,6 +185,9 @@ Connection::_ReceivePacket(void** pbuffer, uint32* psize) result = errno; free(buffer); return result; + } else if (size == 0) { + free(buffer); + return ECONNABORTED; } *pbuffer = buffer; @@ -257,6 +261,15 @@ Connection::Reconnect() } +void +Connection::Disconnect() +{ + int sock = fSock; + fSock = -1; + kclosesocket(sock); +} + + status_t Connection::Init() { diff --git a/src/add-ons/kernel/file_systems/nfs4/Connection.h b/src/add-ons/kernel/file_systems/nfs4/Connection.h index 6ac07d318a..11029c3230 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Connection.h +++ b/src/add-ons/kernel/file_systems/nfs4/Connection.h @@ -39,6 +39,7 @@ public: inline status_t Receive(void** buffer, uint32* size); status_t Reconnect(); + void Disconnect(); static status_t Init(); static status_t CleanUp(); diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp b/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp index f5fa966d54..280be81a68 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp @@ -86,6 +86,8 @@ Server::Server(Connection* conn, ServerAddress* addr) Server::~Server() { fThreadCancel = true; + fConnection->Disconnect(); + interrupt_thread(fThread); delete fConnection; @@ -157,9 +159,12 @@ status_t Server::Repair() { fThreadCancel = true; + interrupt_thread(fThread); + status_t result = fConnection->Reconnect(); if (result != B_OK) return result; + wait_for_thread(fThread, &result); return _StartListening(); } @@ -197,7 +202,8 @@ Server::_Listener() if (req != NULL) { *req->fReply = reply; req->fEvent.NotifyAll(); - } + } else + delete reply; } return B_OK; diff --git a/src/system/kernel/thread.cpp b/src/system/kernel/thread.cpp index 6c95268c44..022b8a1173 100644 --- a/src/system/kernel/thread.cpp +++ b/src/system/kernel/thread.cpp @@ -3007,6 +3007,20 @@ kill_thread(thread_id id) } +status_t +interrupt_thread(thread_id id) +{ + Thread* thread = Thread::GetAndLock(id); + if (thread == NULL) + return B_BAD_THREAD_ID; + BReference threadReference(thread, true); + ThreadLocker threadLocker(thread, true); + + InterruptsSpinLocker schedulerLocker(gSchedulerLock); + return thread_interrupt(thread, false); +} + + status_t send_data(thread_id thread, int32 code, const void *buffer, size_t bufferSize) { From 45aa18ac4c26d8845dfa9ccd7ff566f385ae30ea Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Wed, 30 May 2012 22:48:53 +0200 Subject: [PATCH 017/252] nfs4: Add stub Filesystem class and Mount method --- .../kernel/file_systems/nfs4/Filesystem.cpp | 118 ++++++++++++++++++ .../kernel/file_systems/nfs4/Filesystem.h | 36 ++++++ src/add-ons/kernel/file_systems/nfs4/Jamfile | 1 + .../kernel/file_systems/nfs4/NFS4Defs.h | 3 + 4 files changed, 158 insertions(+) create mode 100644 src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp create mode 100644 src/add-ons/kernel/file_systems/nfs4/Filesystem.h diff --git a/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp b/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp new file mode 100644 index 0000000000..402e67bbe0 --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp @@ -0,0 +1,118 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ + + +#include "Filesystem.h" + +#include + +#include "ReplyInterpreter.h" +#include "RequestBuilder.h" + + +Filesystem::Filesystem() +{ +} + + +Filesystem::~Filesystem() +{ +} + + +status_t +Filesystem::Mount(Filesystem** pfs, RPC::Server* serv, const char* fsPath) +{ + RequestBuilder req(ProcCompound); + req.PutRootFH(); + + // Better way of doing this will be needed + uint32 lookupCount; + char* path = strdup(fsPath); + char* pathStart = path; + char* pathEnd; + while (pathStart != NULL) { + pathEnd = strpbrk(pathStart, "/"); + if (pathEnd != NULL) + *pathEnd = '\0'; + + req.LookUp(pathStart); + + if (pathEnd != NULL && pathEnd[1] != '\0') + pathStart = pathEnd + 1; + else + pathStart = NULL; + + lookupCount++; + } + free(path); + + req.GetFH(); + req.Access(); + Attribute attr[] = { FATTR4_FH_EXPIRE_TYPE }; + req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); + + RPC::Reply *rpl; + serv->SendCall(req.Request(), &rpl); + ReplyInterpreter reply(rpl); + + status_t result; + + result = reply.PutRootFH(); + if (result != B_OK) + return result; + + for (uint32 i = 0; i < lookupCount; i++) { + result = reply.LookUp(); + if (result != B_OK) + return result; + } + + Filehandle fh; + result = reply.GetFH(&fh); + if (result != B_OK) + return result; + + uint32 allowed; + result = reply.Access(NULL, &allowed); + if (result != B_OK) + return result; + else if (allowed & (ACCESS4_READ | ACCESS4_LOOKUP) + != (ACCESS4_READ | ACCESS4_LOOKUP)) + return B_PERMISSION_DENIED; + + AttrValue* values; + uint32 count; + result = reply.GetAttr(&values, &count); + if (result != B_OK) + return result; + + if (count != 1 || values[0].fAttribute != FATTR4_FH_EXPIRE_TYPE) { + delete values; + return B_BAD_VALUE; + } + + // Currently, only persistent filehandles are supported. That will be + // changed soon. + if (values[0].fData.fValue32 != FH4_PERSISTENT) { + delete values; + return B_UNSUPPORTED; + } + + Filesystem* fs = new Filesystem; + fs->fFHExpiryType = values[0].fData.fValue32; + memcpy(&fs->fRootFH, &fh, sizeof(Filehandle)); + fs->fServer = serv; + + delete values; + + *pfs = fs; + + return B_OK; +} + diff --git a/src/add-ons/kernel/file_systems/nfs4/Filesystem.h b/src/add-ons/kernel/file_systems/nfs4/Filesystem.h new file mode 100644 index 0000000000..7489f2e702 --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/Filesystem.h @@ -0,0 +1,36 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ +#ifndef FILESYSTEM_H +#define FILESYSTEM_H + + +#include "NFS4Defs.h" +#include "RPCServer.h" + + +class Filesystem { +public: + static status_t Mount(Filesystem** pfs, RPC::Server* serv, + const char* path); + ~Filesystem(); + + inline uint32 FHExpiryType() const; + +private: + Filesystem(); + + uint32 fFHExpiryType; + + Filehandle fRootFH; + + RPC::Server* fServer; +}; + + +#endif // FILESYSTEM_H + diff --git a/src/add-ons/kernel/file_systems/nfs4/Jamfile b/src/add-ons/kernel/file_systems/nfs4/Jamfile index e58c558db9..bab7e6c8b8 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Jamfile +++ b/src/add-ons/kernel/file_systems/nfs4/Jamfile @@ -4,6 +4,7 @@ UsePrivateHeaders kernel ; KernelAddon nfs4 : Connection.cpp + Filesystem.cpp kernel_interface.cpp ReplyInterpreter.cpp RequestBuilder.cpp diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h index 2762d5f114..b1a4ec7e0f 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h @@ -9,6 +9,9 @@ #define NFS4DEFS_H +#include + + #define NFS4_FHSIZE 128 struct Filehandle { From bf31ee39e56f00cb60142910f1770e0a26b604b5 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Thu, 31 May 2012 00:15:54 +0200 Subject: [PATCH 018/252] nfs4: Add stub Inode class, fix and extend Filesystem class Additionally PUTFH support is added to both RequestBuilder and ReplyInterpreter. --- .../kernel/file_systems/nfs4/Filesystem.cpp | 15 ++++- .../kernel/file_systems/nfs4/Filesystem.h | 22 ++++++++ .../kernel/file_systems/nfs4/Inode.cpp | 55 +++++++++++++++++++ src/add-ons/kernel/file_systems/nfs4/Inode.h | 44 +++++++++++++++ src/add-ons/kernel/file_systems/nfs4/Jamfile | 1 + .../kernel/file_systems/nfs4/NFS4Defs.h | 1 + .../file_systems/nfs4/ReplyInterpreter.h | 8 +++ .../file_systems/nfs4/RequestBuilder.cpp | 16 ++++++ .../kernel/file_systems/nfs4/RequestBuilder.h | 1 + 9 files changed, 161 insertions(+), 2 deletions(-) create mode 100644 src/add-ons/kernel/file_systems/nfs4/Inode.cpp create mode 100644 src/add-ons/kernel/file_systems/nfs4/Inode.h diff --git a/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp b/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp index 402e67bbe0..282a33d3e8 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp @@ -14,8 +14,12 @@ #include "ReplyInterpreter.h" #include "RequestBuilder.h" +#include "Inode.h" + Filesystem::Filesystem() + : + fId(0) { } @@ -32,7 +36,7 @@ Filesystem::Mount(Filesystem** pfs, RPC::Server* serv, const char* fsPath) req.PutRootFH(); // Better way of doing this will be needed - uint32 lookupCount; + uint32 lookupCount = 0; char* path = strdup(fsPath); char* pathStart = path; char* pathEnd; @@ -104,7 +108,7 @@ Filesystem::Mount(Filesystem** pfs, RPC::Server* serv, const char* fsPath) return B_UNSUPPORTED; } - Filesystem* fs = new Filesystem; + Filesystem* fs = new(std::nothrow) Filesystem; fs->fFHExpiryType = values[0].fData.fValue32; memcpy(&fs->fRootFH, &fh, sizeof(Filehandle)); fs->fServer = serv; @@ -116,3 +120,10 @@ Filesystem::Mount(Filesystem** pfs, RPC::Server* serv, const char* fsPath) return B_OK; } + +Inode* +Filesystem::CreateRootInode() +{ + return new(std::nothrow)Inode(this, fRootFH); +} + diff --git a/src/add-ons/kernel/file_systems/nfs4/Filesystem.h b/src/add-ons/kernel/file_systems/nfs4/Filesystem.h index 7489f2e702..ca370c28de 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Filesystem.h +++ b/src/add-ons/kernel/file_systems/nfs4/Filesystem.h @@ -13,13 +13,19 @@ #include "RPCServer.h" +class Inode; + class Filesystem { public: static status_t Mount(Filesystem** pfs, RPC::Server* serv, const char* path); ~Filesystem(); + Inode* CreateRootInode(); + inline uint32 FHExpiryType() const; + inline RPC::Server* Server(); + inline uint64 GetId(); private: Filesystem(); @@ -29,8 +35,24 @@ private: Filehandle fRootFH; RPC::Server* fServer; + + vint64 fId; }; +inline RPC::Server* +Filesystem::Server() +{ + return fServer; +} + + +inline uint64 +Filesystem::GetId() +{ + return atomic_add64(&fId, 1); +} + + #endif // FILESYSTEM_H diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp new file mode 100644 index 0000000000..f2af559ca4 --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -0,0 +1,55 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ + + +#include "Inode.h" + +#include + +#include "ReplyInterpreter.h" +#include "RequestBuilder.h" + + +// Creating Inode object from Filehandle probably is not a good idea when +// filehandles are volatile. +Inode::Inode(Filesystem* fs, const Filehandle &fh) + : + fFilesystem(fs) +{ + memcpy(&fHandle, &fh, sizeof(fh)); + + RequestBuilder req(ProcCompound); + req.PutFH(fh); + + Attribute attr[] = { FATTR4_FILEID }; + req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); + + RPC::Reply *rpl; + fs->Server()->SendCall(req.Request(), &rpl); + ReplyInterpreter reply(rpl); + + status_t result; + result = reply.PutFH(); + if (result != B_OK) + return; + + AttrValue* values; + uint32 count; + result = reply.GetAttr(&values, &count); + if (result != B_OK) + return; + + if (count < 1 || values[0].fAttribute != FATTR4_FILEID) { + // Server does not provide fileid. We need to make something up. + fFileId = fs->GetId(); + } else + fFileId = values[0].fData.fValue64; + + delete values; +} + diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h b/src/add-ons/kernel/file_systems/nfs4/Inode.h new file mode 100644 index 0000000000..39d9ea4514 --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -0,0 +1,44 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ +#ifndef INODE_H +#define INODE_H + + +#include + +#include "Filesystem.h" +#include "NFS4Defs.h" + + +class Inode { +public: + Inode(Filesystem* fs, const Filehandle &fh); + + inline ino_t ID() const; + +private: + uint64 fFileId; + + Filehandle fHandle; + Filesystem* fFilesystem; +}; + + +inline ino_t +Inode::ID() const +{ + if (sizeof(ino_t) >= sizeof(uint64)) + return fFileId; + else + return (ino_t)fFileId ^ (fFileId >> + (sizeof(uint64) - sizeof(ino_t)) * 8); +} + + +#endif // INODE_H + diff --git a/src/add-ons/kernel/file_systems/nfs4/Jamfile b/src/add-ons/kernel/file_systems/nfs4/Jamfile index bab7e6c8b8..81f3f46b8a 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Jamfile +++ b/src/add-ons/kernel/file_systems/nfs4/Jamfile @@ -5,6 +5,7 @@ UsePrivateHeaders kernel ; KernelAddon nfs4 : Connection.cpp Filesystem.cpp + Inode.cpp kernel_interface.cpp ReplyInterpreter.cpp RequestBuilder.cpp diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h index b1a4ec7e0f..5938eff370 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h @@ -29,6 +29,7 @@ enum Opcode { OpGetAttr = 9, OpGetFH = 10, OpLookUp = 15, + OpPutFH = 22, OpPutRootFH = 24 }; diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h index 83973b17dd..4361095bc7 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h @@ -33,6 +33,7 @@ public: status_t GetAttr(AttrValue** attrs, uint32* count); status_t GetFH(Filehandle* fh); inline status_t LookUp(); + inline status_t PutFH(); inline status_t PutRootFH(); private: @@ -51,6 +52,13 @@ ReplyInterpreter::LookUp() } +inline status_t +ReplyInterpreter::PutFH() +{ + return _OperationError(OpPutFH); +} + + inline status_t ReplyInterpreter::PutRootFH() { diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp index 341d54385a..2ed5b59df5 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp @@ -114,6 +114,22 @@ RequestBuilder::LookUp(const char* name) } +status_t +RequestBuilder::PutFH(const Filehandle& fh) +{ + if (fProcedure != ProcCompound) + return B_BAD_VALUE; + if (fRequest == NULL) + return B_NO_MEMORY; + + fRequest->Stream().AddUInt(OpPutFH); + fRequest->Stream().AddOpaque(fh.fFH, fh.fSize); + fOpCount++; + + return B_OK; +} + + status_t RequestBuilder::PutRootFH() { diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h index 377519f15c..7f8b3b3ba1 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h @@ -25,6 +25,7 @@ public: status_t GetAttr(Attribute* attrs, uint32 count); status_t GetFH(); status_t LookUp(const char* name); + status_t PutFH(const Filehandle& fh); status_t PutRootFH(); RPC::Call* Request(); From d38e98d806f2ac17786ca558c16ebbfeb3e770f8 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Thu, 31 May 2012 00:42:02 +0200 Subject: [PATCH 019/252] nfs4: Implement nfs4_mount() procedure --- .../kernel/file_systems/nfs4/Inode.cpp | 11 +++-- src/add-ons/kernel/file_systems/nfs4/Inode.h | 9 ++++ .../kernel/file_systems/nfs4/NFS4Defs.h | 19 ++++++++ .../file_systems/nfs4/kernel_interface.cpp | 46 ++++++++++--------- 4 files changed, 60 insertions(+), 25 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index f2af559ca4..eecf8358ce 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -26,7 +26,7 @@ Inode::Inode(Filesystem* fs, const Filehandle &fh) RequestBuilder req(ProcCompound); req.PutFH(fh); - Attribute attr[] = { FATTR4_FILEID }; + Attribute attr[] = { FATTR4_TYPE, FATTR4_FILEID }; req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); RPC::Reply *rpl; @@ -41,14 +41,17 @@ Inode::Inode(Filesystem* fs, const Filehandle &fh) AttrValue* values; uint32 count; result = reply.GetAttr(&values, &count); - if (result != B_OK) + if (result != B_OK || count < 1) return; - if (count < 1 || values[0].fAttribute != FATTR4_FILEID) { + if (count < 2 || values[1].fAttribute != FATTR4_FILEID) { // Server does not provide fileid. We need to make something up. fFileId = fs->GetId(); } else - fFileId = values[0].fData.fValue64; + fFileId = values[1].fData.fValue64; + + // FATTR4_TYPE is mandatory + fType = values[0].fData.fValue32; delete values; } diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h b/src/add-ons/kernel/file_systems/nfs4/Inode.h index 39d9ea4514..1d878cd014 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -20,9 +20,11 @@ public: Inode(Filesystem* fs, const Filehandle &fh); inline ino_t ID() const; + inline mode_t Type() const; private: uint64 fFileId; + uint32 fType; Filehandle fHandle; Filesystem* fFilesystem; @@ -40,5 +42,12 @@ Inode::ID() const } +inline mode_t +Inode::Type() const +{ + return sNFSFileTypeToHaiku[fType]; +} + + #endif // INODE_H diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h index 5938eff370..7c2f3dad2e 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h @@ -9,6 +9,8 @@ #define NFS4DEFS_H +#include + #include @@ -104,6 +106,23 @@ enum Attribute { FATTR4_MOUNTED_ON_FILEID = 55 }; +enum FileType { + NF4REG = 1, /* Regular File */ + NF4DIR = 2, /* Directory */ + NF4BLK = 3, /* Special File - block device */ + NF4CHR = 4, /* Special File - character device */ + NF4LNK = 5, /* Symbolic Link */ + NF4SOCK = 6, /* Special File - socket */ + NF4FIFO = 7, /* Special File - fifo */ + NF4ATTRDIR = 8, /* Attribute Directory */ + NF4NAMEDATTR = 9 /* Named Attribute */ +}; + +static const mode_t sNFSFileTypeToHaiku[] = { + S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, S_IFSOCK, S_IFIFO, S_IFDIR, + S_IFREG +}; + enum FileHandleExpiryType { FH4_PERSISTENT = 0x00, FH4_NOEXPIRE_WITH_OPEN = 0x01, 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 111a2ddad2..078a3457d6 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -11,10 +11,11 @@ #include "Connection.h" #include "RPCServer.h" - - -#define NFS_PROC_NULL 0 -#define NFS_PROC_COMPOUND 1 +#include "NFS4Defs.h" +#include "Inode.h" +#include "RequestBuilder.h" +#include "ReplyInterpreter.h" +#include "Filesystem.h" extern fs_volume_ops gNFSv4VolumeOps; @@ -31,30 +32,33 @@ static status_t nfs4_mount(fs_volume* volume, const char* device, uint32 flags, const char* args, ino_t* _rootVnodeID) { - dprintf("NFS4 Mounting...\n"); + status_t result; - RPC::Server *s; + RPC::Server *server; // hardcoded ip 192.168.1.70 - gRPCServerManager->Acquire(&s, 0xc0a80146, 2049, ProtocolTCP); + result = gRPCServerManager->Acquire(&server, 0xc0a80146, 2049, ProtocolUDP); + if (result != B_OK) + return result; - RPC::Reply *r; - RPC::Call *c = RPC::Call::Create(NFS_PROC_NULL, RPC::Auth::CreateSys(), - RPC::Auth::CreateNone()); - s->SendCall(c, &r); - delete r; - delete c; - gRPCServerManager->Release(s); + Filesystem* fs; + // hardcoded path + result = Filesystem::Mount(&fs, server, "haiku/src/add-ons/kernel"); + if (result != B_OK) { + gRPCServerManager->Release(server); + return result; + } + Inode* inode = fs->CreateRootInode(); + + volume->private_volume = fs; volume->ops = &gNFSv4VolumeOps; - status_t error = publish_vnode(volume, 0, (void*)0xdeadbeef, - &gNFSv4VnodeOps, S_IFDIR, 0); - if (error != B_OK) - return error; + result = publish_vnode(volume, inode->ID(), inode, &gNFSv4VnodeOps, + inode->Type(), 0); + if (result != B_OK) + return result; - *_rootVnodeID = 0; - - dprintf("NFS4 Mounted\n"); + *_rootVnodeID = inode->ID(); return B_OK; } From 212de7205336baeee1889f9d5fb595e028b19a83 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Thu, 31 May 2012 02:08:59 +0200 Subject: [PATCH 020/252] nfs4: Add basic nfs4_read_stat() procedure Not all data are retrieved and there is a room for improvement in handling situations when server does not provide necessary information. --- .../kernel/file_systems/nfs4/Inode.cpp | 51 +++++++++++++++++++ src/add-ons/kernel/file_systems/nfs4/Inode.h | 4 ++ .../kernel/file_systems/nfs4/NFS4Defs.h | 4 +- .../file_systems/nfs4/ReplyInterpreter.cpp | 20 +++++++- .../file_systems/nfs4/kernel_interface.cpp | 37 +++++++++++++- 5 files changed, 112 insertions(+), 4 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index eecf8358ce..80688d61d6 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -56,3 +56,54 @@ Inode::Inode(Filesystem* fs, const Filehandle &fh) delete values; } + +status_t +Inode::Stat(struct stat* st) +{ + RequestBuilder req(ProcCompound); + req.PutFH(fHandle); + + Attribute attr[] = { FATTR4_SIZE, FATTR4_MODE, FATTR4_NUMLINKS }; + req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); + + RPC::Reply *rpl; + fFilesystem->Server()->SendCall(req.Request(), &rpl); + ReplyInterpreter reply(rpl); + + status_t result; + result = reply.PutFH(); + if (result != B_OK) + return result; + + AttrValue* values; + uint32 count; + result = reply.GetAttr(&values, &count); + if (result != B_OK) + return result; + + // FATTR4_SIZE is mandatory + if (count < 1 || values[0].fAttribute != FATTR4_SIZE) + return B_BAD_VALUE; + st->st_size = values[0].fData.fValue64; + + uint32 next = 1; + st->st_mode = Type(); + if (count >= next && values[next].fAttribute == FATTR4_MODE) { + st->st_mode |= values[next].fData.fValue32; + next++; + } + // TODO: else: get some info from ACCESS + + if (count >= next && values[next].fAttribute == FATTR4_NUMLINKS) { + st->st_nlink = values[next].fData.fValue32; + next++; + } else + st->st_nlink = 1; // TODO: if !link_support we dont have to ask + + st->st_uid = 0; + st->st_gid = 0; + + delete values; + 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 1d878cd014..73ce182296 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -9,6 +9,8 @@ #define INODE_H +#include + #include #include "Filesystem.h" @@ -22,6 +24,8 @@ public: inline ino_t ID() const; inline mode_t Type() const; + status_t Stat(struct stat* st); + private: uint64 fFileId; uint32 fType; diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h index 7c2f3dad2e..f9f4622fde 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h @@ -119,8 +119,8 @@ enum FileType { }; static const mode_t sNFSFileTypeToHaiku[] = { - S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, S_IFSOCK, S_IFIFO, S_IFDIR, - S_IFREG + S_IFREG, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, S_IFSOCK, S_IFIFO, + S_IFDIR, S_IFREG }; enum FileHandleExpiryType { diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp index 4ff308137d..1cb5158609 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp @@ -83,7 +83,7 @@ ReplyInterpreter::GetAttr(AttrValue** attrs, uint32* count) uint32 attr_count = 0; for (uint32 i = 0; i < bcount; i++) { bitmap[i] = fReply->Stream().GetUInt(); - attr_count = sCountBits(bitmap[i]); + attr_count += sCountBits(bitmap[i]); } uint32 size; @@ -110,12 +110,30 @@ ReplyInterpreter::GetAttr(AttrValue** attrs, uint32* count) current++; } + if (sIsAttrSet(FATTR4_SIZE, bitmap, bcount)) { + values[current].fAttribute = FATTR4_SIZE; + values[current].fData.fValue64 = stream.GetUHyper(); + current++; + } + if (sIsAttrSet(FATTR4_FILEID, bitmap, bcount)) { values[current].fAttribute = FATTR4_FILEID; values[current].fData.fValue64 = stream.GetUHyper(); current++; } + if (sIsAttrSet(FATTR4_MODE, bitmap, bcount)) { + values[current].fAttribute = FATTR4_MODE; + values[current].fData.fValue32 = stream.GetUInt(); + current++; + } + + if (sIsAttrSet(FATTR4_NUMLINKS, bitmap, bcount)) { + values[current].fAttribute = FATTR4_NUMLINKS; + values[current].fData.fValue32 = stream.GetUInt(); + current++; + } + delete bitmap; *count = attr_count; 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 078a3457d6..02214dac6e 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -79,6 +79,14 @@ nfs4_put_vnode(fs_volume* volume, fs_vnode* vnode, bool reenter) } +static status_t +nfs4_read_stat(fs_volume* volume, fs_vnode* vnode, struct stat* stat) +{ + Inode* inode = reinterpret_cast(vnode->private_node); + return inode->Stat(stat); +} + + status_t nfs4_init() { @@ -130,7 +138,34 @@ fs_volume_ops gNFSv4VolumeOps = { fs_vnode_ops gNFSv4VnodeOps = { NULL, // lookup() NULL, // get_vnode_name() - &nfs4_put_vnode + &nfs4_put_vnode, + NULL, // remove_vnode() + + /* VM file access */ + NULL, // can_page() + NULL, // read_pages() + NULL, // write_pages() + + NULL, // io() + NULL, // cancel_io() + + NULL, // get_file_map() + + NULL, // ioctl() + NULL, + NULL, // fs_select() + NULL, // fs_deselect() + NULL, // fsync() + + NULL, // read_link() + NULL, // create_symlink() + + NULL, // link() + NULL, // unlink() + NULL, // rename() + + NULL, // access() + &nfs4_read_stat, }; static file_system_module_info sNFSv4ModuleInfo = { From cbe0913aa086ac18b7dfe2c51b3e86f0286feac0 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Thu, 31 May 2012 13:19:41 +0200 Subject: [PATCH 021/252] nfs4: Fix RPC::ServerManager release bug RPC::ServerManager did not check whether reference counter equals 0 before destroying RPC::Server object. --- src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp b/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp index 280be81a68..fed27887e6 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp @@ -304,15 +304,13 @@ ServerManager::Release(Server* serv) if (node != NULL) { node->fRefCount--; - if (node->fRefCount == 0) + if (node->fRefCount == 0) { _Delete(node); + delete node->fServer; + delete node; + } } mutex_unlock(&fLock); - - if (node != NULL) { - delete node->fServer; - delete node; - } } From c1a7ba322d4278cf32ef978573f70a074a7671dc Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Thu, 31 May 2012 13:21:28 +0200 Subject: [PATCH 022/252] nfs4: Add unmount() and put_vnode() procedures --- .../kernel/file_systems/nfs4/kernel_interface.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) 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 02214dac6e..b67a1a1d51 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -67,7 +67,12 @@ nfs4_mount(fs_volume* volume, const char* device, uint32 flags, static status_t nfs4_unmount(fs_volume* volume) { - dprintf("NFS4 Unmounting...\n"); + Filesystem* fs = reinterpret_cast(volume->private_volume); + RPC::Server* server = fs->Server(); + + delete fs; + gRPCServerManager->Release(server); + return B_OK; } @@ -75,6 +80,9 @@ nfs4_unmount(fs_volume* volume) static status_t nfs4_put_vnode(fs_volume* volume, fs_vnode* vnode, bool reenter) { + Inode* inode = reinterpret_cast(vnode->private_node); + delete inode; + return B_OK; } From 821f13b0779e068d43bdd380b4c9791a1aec3832 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Thu, 31 May 2012 13:47:38 +0200 Subject: [PATCH 023/252] nfs4: Add open_dir, close_dir and free_dir_cookie hooks --- .../kernel/file_systems/nfs4/Inode.cpp | 31 +++++++++++ src/add-ons/kernel/file_systems/nfs4/Inode.h | 1 + .../file_systems/nfs4/kernel_interface.cpp | 51 +++++++++++++++++++ 3 files changed, 83 insertions(+) diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index 80688d61d6..630e1fdad6 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -107,3 +107,34 @@ Inode::Stat(struct stat* st) return B_OK; } + +status_t +Inode::OpenDir(uint64* cookie) +{ + if (fType != NF4DIR) + return B_NOT_A_DIRECTORY; + + RequestBuilder req(ProcCompound); + req.PutFH(fHandle); + req.Access(); + + RPC::Reply *rpl; + fFilesystem->Server()->SendCall(req.Request(), &rpl); + ReplyInterpreter reply(rpl); + + status_t result; + result = reply.PutFH(); + if (result != B_OK) + return result; + + uint32 allowed; + result = reply.Access(NULL, &allowed); + if (result != B_OK) + return result; + + if (allowed & ACCESS4_READ != ACCESS4_READ) + return B_PERMISSION_DENIED; + + 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 73ce182296..e9ed6ca588 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -25,6 +25,7 @@ public: inline mode_t Type() const; status_t Stat(struct stat* st); + status_t OpenDir(uint64* cookie); private: uint64 fFileId; 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 b67a1a1d51..df9be9f1e3 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -95,6 +95,38 @@ nfs4_read_stat(fs_volume* volume, fs_vnode* vnode, struct stat* stat) } +static status_t +nfs4_open_dir(fs_volume* volume, fs_vnode* vnode, void** _cookie) +{ + uint64* cookie = new(std::nothrow) uint64; + if (cookie == NULL) + return B_NO_MEMORY; + *_cookie = cookie; + + Inode* inode = reinterpret_cast(vnode->private_node); + status_t result = inode->OpenDir(cookie); + if (result != B_OK) + delete cookie; + + return result; +} + + +static status_t +nfs4_close_dir(fs_volume* volume, fs_vnode* vnode, void* cookie) +{ + return B_OK; +} + + +static status_t +nfs4_free_dir_cookie(fs_volume* volume, fs_vnode* vnode, void* cookie) +{ + delete reinterpret_cast(cookie); + return B_OK; +} + + status_t nfs4_init() { @@ -174,6 +206,25 @@ fs_vnode_ops gNFSv4VnodeOps = { NULL, // access() &nfs4_read_stat, + NULL, // write_stat() + NULL, // fs_preallocate() + + /* file operations */ + NULL, // create() + NULL, // open() + NULL, // close() + NULL, // free_cookie() + NULL, // read() + NULL, // write, + + /* directory operations */ + NULL, // create_dir() + NULL, // remove_dir() + nfs4_open_dir, + nfs4_close_dir, + nfs4_free_dir_cookie, + NULL, // read_dir() + NULL, // rewind_dir, }; static file_system_module_info sNFSv4ModuleInfo = { From 4b48348f9747400f0a2b63544e2806b1e6943215 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Thu, 31 May 2012 18:06:21 +0200 Subject: [PATCH 024/252] nfs4: Add read_dir() hook --- .../kernel/file_systems/nfs4/Filesystem.cpp | 12 +- .../kernel/file_systems/nfs4/Filesystem.h | 11 +- .../kernel/file_systems/nfs4/Inode.cpp | 134 +++++++++++++++++- src/add-ons/kernel/file_systems/nfs4/Inode.h | 47 ++++-- .../kernel/file_systems/nfs4/NFS4Defs.h | 3 +- .../file_systems/nfs4/ReplyInterpreter.cpp | 113 +++++++++++---- .../file_systems/nfs4/ReplyInterpreter.h | 13 ++ .../file_systems/nfs4/RequestBuilder.cpp | 57 ++++++-- .../kernel/file_systems/nfs4/RequestBuilder.h | 5 + .../file_systems/nfs4/kernel_interface.cpp | 19 ++- 10 files changed, 347 insertions(+), 67 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp b/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp index 282a33d3e8..b7149b08fc 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp @@ -30,7 +30,8 @@ Filesystem::~Filesystem() status_t -Filesystem::Mount(Filesystem** pfs, RPC::Server* serv, const char* fsPath) +Filesystem::Mount(Filesystem** pfs, RPC::Server* serv, const char* fsPath, + dev_t id) { RequestBuilder req(ProcCompound); req.PutRootFH(); @@ -97,14 +98,14 @@ Filesystem::Mount(Filesystem** pfs, RPC::Server* serv, const char* fsPath) return result; if (count != 1 || values[0].fAttribute != FATTR4_FH_EXPIRE_TYPE) { - delete values; + delete[] values; return B_BAD_VALUE; } // Currently, only persistent filehandles are supported. That will be // changed soon. if (values[0].fData.fValue32 != FH4_PERSISTENT) { - delete values; + delete[] values; return B_UNSUPPORTED; } @@ -112,8 +113,9 @@ Filesystem::Mount(Filesystem** pfs, RPC::Server* serv, const char* fsPath) fs->fFHExpiryType = values[0].fData.fValue32; memcpy(&fs->fRootFH, &fh, sizeof(Filehandle)); fs->fServer = serv; + fs->fDevId = id; - delete values; + delete[] values; *pfs = fs; @@ -124,6 +126,6 @@ Filesystem::Mount(Filesystem** pfs, RPC::Server* serv, const char* fsPath) Inode* Filesystem::CreateRootInode() { - return new(std::nothrow)Inode(this, fRootFH); + return new(std::nothrow)Inode(this, fRootFH, NULL); } diff --git a/src/add-ons/kernel/file_systems/nfs4/Filesystem.h b/src/add-ons/kernel/file_systems/nfs4/Filesystem.h index ca370c28de..a9386de8d2 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Filesystem.h +++ b/src/add-ons/kernel/file_systems/nfs4/Filesystem.h @@ -18,7 +18,7 @@ class Inode; class Filesystem { public: static status_t Mount(Filesystem** pfs, RPC::Server* serv, - const char* path); + const char* path, dev_t id); ~Filesystem(); Inode* CreateRootInode(); @@ -27,6 +27,7 @@ public: inline RPC::Server* Server(); inline uint64 GetId(); + inline dev_t DevId() const; private: Filesystem(); @@ -37,6 +38,7 @@ private: RPC::Server* fServer; vint64 fId; + dev_t fDevId; }; @@ -54,5 +56,12 @@ Filesystem::GetId() } +inline dev_t +Filesystem::DevId() const +{ + return fDevId; +} + + #endif // FILESYSTEM_H diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index 630e1fdad6..329730f634 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -9,6 +9,7 @@ #include "Inode.h" +#include #include #include "ReplyInterpreter.h" @@ -17,9 +18,10 @@ // Creating Inode object from Filehandle probably is not a good idea when // filehandles are volatile. -Inode::Inode(Filesystem* fs, const Filehandle &fh) +Inode::Inode(Filesystem* fs, const Filehandle &fh, Inode* parent) : - fFilesystem(fs) + fFilesystem(fs), + fParent(parent) { memcpy(&fHandle, &fh, sizeof(fh)); @@ -53,7 +55,7 @@ Inode::Inode(Filesystem* fs, const Filehandle &fh) // FATTR4_TYPE is mandatory fType = values[0].fData.fValue32; - delete values; + delete[] values; } @@ -82,8 +84,10 @@ Inode::Stat(struct stat* st) return result; // FATTR4_SIZE is mandatory - if (count < 1 || values[0].fAttribute != FATTR4_SIZE) + if (count < 1 || values[0].fAttribute != FATTR4_SIZE) { + delete[] values; return B_BAD_VALUE; + } st->st_size = values[0].fData.fValue64; uint32 next = 1; @@ -103,7 +107,7 @@ Inode::Stat(struct stat* st) st->st_uid = 0; st->st_gid = 0; - delete values; + delete[] values; return B_OK; } @@ -135,6 +139,126 @@ Inode::OpenDir(uint64* cookie) if (allowed & ACCESS4_READ != ACCESS4_READ) return B_PERMISSION_DENIED; + cookie[0] = 0; + cookie[1] = 2; + + return B_OK; +} + + +status_t +Inode::_ReadDirOnce(DirEntry** dirents, uint32* count, uint64* cookie, + bool* eof) +{ + RequestBuilder req(ProcCompound); + req.PutFH(fHandle); + + Attribute attr[] = { FATTR4_FILEID }; + req.ReadDir(*count, cookie, attr, sizeof(attr) / sizeof(Attribute)); + + RPC::Reply *rpl; + fFilesystem->Server()->SendCall(req.Request(), &rpl); + ReplyInterpreter reply(rpl); + + status_t result; + result = reply.PutFH(); + if (result != B_OK) + return result; + + return reply.ReadDir(cookie, dirents, count, eof); +} + + +status_t +Inode::_FillDirEntry(struct dirent* de, ino_t id, const char* name, uint32 pos, + uint32 size) +{ + uint32 nameSize = strlen(name); + const uint32 entSize = sizeof(struct dirent); + + if (pos + entSize + nameSize > size) + return B_BUFFER_OVERFLOW; + + de->d_dev = fFilesystem->DevId(); + de->d_ino = id; + de->d_reclen = entSize + nameSize; + if (de->d_reclen % 8 != 0) + de->d_reclen += 8 - de->d_reclen % 8; + + strcpy(de->d_name, name); + + return B_OK; +} + + +status_t +Inode::ReadDir(void* _buffer, uint32 size, uint32* _count, uint64* cookie) +{ + uint32 count = 0; + uint32 pos = 0; + uint32 this_count; + bool eof = false; + + char* buffer = reinterpret_cast(_buffer); + + if (cookie[0] == 0 && cookie[1] == 2 && count < *_count) { + struct dirent* de = reinterpret_cast(buffer + pos); + + _FillDirEntry(de, fFileId, ".", pos, size); + + pos += de->d_reclen; + count++; + cookie[1]--; + } + + if (cookie[0] == 0 && cookie[1] == 1 && count < *_count) { + struct dirent* de = reinterpret_cast(buffer + pos); + + if (fParent != NULL) + _FillDirEntry(de, fParent->fFileId, "..", pos, size); + else + _FillDirEntry(de, fFileId, "..", pos, size); + + pos += de->d_reclen; + count++; + cookie[1]--; + } + + while (count < *_count && !eof) { + this_count = *_count; + DirEntry* dirents; + + status_t result = _ReadDirOnce(&dirents, &this_count, cookie, &eof); + if (result != B_OK) + return result; + + uint32 i; + for (i = 0; i < this_count; i++) { + struct dirent* de = reinterpret_cast(buffer + pos); + + ino_t id; + if (dirents[i].fAttrCount == 1) + id = _FileIdToInoT(dirents[i].fAttrs[0].fData.fValue64); + else + id = _FileIdToInoT(fFilesystem->GetId()); + + const char* name = dirents[i].fName; + if (_FillDirEntry(de, id, name, pos, size) == B_BUFFER_OVERFLOW) { + eof = true; + break; + } + + pos += de->d_reclen; + } + delete[] dirents; + count += i; + } + + if (count == 0 && this_count > 0) + return B_BUFFER_OVERFLOW; + + *_count = count; + 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 e9ed6ca588..b7a8528766 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -15,35 +15,54 @@ #include "Filesystem.h" #include "NFS4Defs.h" +#include "ReplyInterpreter.h" class Inode { public: - Inode(Filesystem* fs, const Filehandle &fh); + Inode(Filesystem* fs, const Filehandle &fh, + Inode* parent); - inline ino_t ID() const; - inline mode_t Type() const; + inline ino_t ID() const; + inline mode_t Type() const; - status_t Stat(struct stat* st); - status_t OpenDir(uint64* cookie); + status_t Stat(struct stat* st); + status_t OpenDir(uint64* cookie); + status_t ReadDir(void* buffer, uint32 size, + uint32* count, uint64* cookie); private: - uint64 fFileId; - uint32 fType; + status_t _ReadDirOnce(DirEntry** dirents, uint32* count, + uint64* cookie, bool* eof); + status_t _FillDirEntry(struct dirent* de, ino_t id, + const char* name, uint32 pos, uint32 size); - Filehandle fHandle; - Filesystem* fFilesystem; + static inline ino_t _FileIdToInoT(uint64 fileid); + + uint64 fFileId; + uint32 fType; + + Filehandle fHandle; + Filesystem* fFilesystem; + Inode* fParent; }; +inline ino_t +Inode::_FileIdToInoT(uint64 fileid) +{ + if (sizeof(ino_t) >= sizeof(uint64)) + return fileid; + else + return (ino_t)fileid ^ (fileid >> + (sizeof(uint64) - sizeof(ino_t)) * 8); +} + + inline ino_t Inode::ID() const { - if (sizeof(ino_t) >= sizeof(uint64)) - return fFileId; - else - return (ino_t)fFileId ^ (fFileId >> - (sizeof(uint64) - sizeof(ino_t)) * 8); + return _FileIdToInoT(fFileId); } diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h index f9f4622fde..3ea863096f 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h @@ -32,7 +32,8 @@ enum Opcode { OpGetFH = 10, OpLookUp = 15, OpPutFH = 22, - OpPutRootFH = 24 + OpPutRootFH = 24, + OpReadDir = 26 }; enum Access { diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp index 1cb5158609..b0137b01f9 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp @@ -14,6 +14,22 @@ #include +DirEntry::DirEntry() + : + fName(NULL), + fAttrs(NULL), + fAttrCount(0) +{ +} + + +DirEntry::~DirEntry() +{ + free(const_cast(fName)); + delete[] fAttrs; +} + + ReplyInterpreter::ReplyInterpreter(RPC::Reply* reply) : fReply(reply) @@ -75,6 +91,74 @@ ReplyInterpreter::GetAttr(AttrValue** attrs, uint32* count) if (res != B_OK) return res; + return _DecodeAttrs(fReply->Stream(), attrs, count); +} + + +status_t +ReplyInterpreter::GetFH(Filehandle* fh) +{ + status_t res = _OperationError(OpGetFH); + if (res != B_OK) + return res; + + uint32 size; + const void* ptr = fReply->Stream().GetOpaque(&size); + if (ptr == NULL || size > NFS4_FHSIZE) + return B_BAD_VALUE; + + if (fh != NULL) { + fh->fSize = size; + memcpy(fh->fFH, ptr, size); + } + + return B_OK; +} + + +status_t +ReplyInterpreter::ReadDir(uint64* cookie, DirEntry** dirents, uint32* _count, + bool* eof) +{ + status_t res = _OperationError(OpReadDir); + if (res != B_OK) + return res; + + cookie[1] = fReply->Stream().GetUHyper(); + + bool isNext; + uint32 count = 0; + DirEntry* entries = new(std::nothrow) DirEntry[*_count]; + if (entries == NULL) + return B_NO_MEMORY; + + isNext = fReply->Stream().GetBoolean(); + while (isNext && count <= *_count) { + cookie[0] = fReply->Stream().GetUHyper(); + + entries[count].fName = fReply->Stream().GetString(); + _DecodeAttrs(fReply->Stream(), &entries[count].fAttrs, + &entries[count].fAttrCount); + + count++; + + isNext = fReply->Stream().GetBoolean(); + } + if (!isNext) + *eof = fReply->Stream().GetBoolean(); + else + *eof = false; + + *_count = count; + *dirents = entries; + + return B_OK; +} + +status_t +ReplyInterpreter::_DecodeAttrs(XDR::ReadStream& str, AttrValue** attrs, + uint32* count) +{ uint32 bcount = fReply->Stream().GetUInt(); uint32 *bitmap = new(std::nothrow) uint32[bcount]; if (bitmap == NULL) @@ -82,17 +166,17 @@ ReplyInterpreter::GetAttr(AttrValue** attrs, uint32* count) uint32 attr_count = 0; for (uint32 i = 0; i < bcount; i++) { - bitmap[i] = fReply->Stream().GetUInt(); + bitmap[i] = str.GetUInt(); attr_count += sCountBits(bitmap[i]); } uint32 size; - const void* ptr = fReply->Stream().GetOpaque(&size); + const void* ptr = str.GetOpaque(&size); XDR::ReadStream stream(const_cast(ptr), size); AttrValue* values = new(std::nothrow) AttrValue[attr_count]; if (values == NULL) { - delete bitmap; + delete[] bitmap; return B_NO_MEMORY; } @@ -134,7 +218,7 @@ ReplyInterpreter::GetAttr(AttrValue** attrs, uint32* count) current++; } - delete bitmap; + delete[] bitmap; *count = attr_count; *attrs = values; @@ -142,27 +226,6 @@ ReplyInterpreter::GetAttr(AttrValue** attrs, uint32* count) } -status_t -ReplyInterpreter::GetFH(Filehandle* fh) -{ - status_t res = _OperationError(OpGetFH); - if (res != B_OK) - return res; - - uint32 size; - const void* ptr = fReply->Stream().GetOpaque(&size); - if (ptr == NULL || size > NFS4_FHSIZE) - return B_BAD_VALUE; - - if (fh != NULL) { - fh->fSize = size; - memcpy(fh->fFH, ptr, size); - } - - return B_OK; -} - - status_t ReplyInterpreter::_OperationError(Opcode op) { diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h index 4361095bc7..8eebf24b9e 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h @@ -24,6 +24,15 @@ struct AttrValue { } fData; }; +struct DirEntry { + const char* fName; + AttrValue* fAttrs; + uint32 fAttrCount; + + DirEntry(); + ~DirEntry(); +}; + class ReplyInterpreter { public: ReplyInterpreter(RPC::Reply* reply); @@ -35,8 +44,12 @@ public: inline status_t LookUp(); inline status_t PutFH(); inline status_t PutRootFH(); + status_t ReadDir(uint64* cookie, DirEntry** dirents, + uint32* count, bool* eof); private: + status_t _DecodeAttrs(XDR::ReadStream& stream, AttrValue** attrs, + uint32* count); status_t _OperationError(Opcode op); static status_t _NFS4ErrorToHaiku(uint32 x); diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp index 2ed5b59df5..2e9bfe7f04 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp @@ -62,18 +62,7 @@ RequestBuilder::GetAttr(Attribute* attrs, uint32 count) return B_NO_MEMORY; fRequest->Stream().AddUInt(OpGetAttr); - - // 2 is safe in NFS4, not in NFS4.1 though - uint32 bitmap[2]; - memset(bitmap, 0, sizeof(bitmap)); - for (uint32 i = 0; i < count; i++) { - bitmap[attrs[i] / 32] |= 1 << attrs[i] % 32; - } - - uint32 bcount = bitmap[1] != 0 ? 2 : 1; - fRequest->Stream().AddUInt(bcount); - for (uint32 i = 0; i < bcount; i++) - fRequest->Stream().AddUInt(bitmap[i]); + _AttrBitmap(fRequest->Stream(), attrs, count); fOpCount++; @@ -145,6 +134,32 @@ RequestBuilder::PutRootFH() } +status_t +RequestBuilder::ReadDir(uint32 count, uint64* cookie, Attribute* attrs, + uint32 attr_count) +{ + (void)count; + + if (fProcedure != ProcCompound) + return B_BAD_VALUE; + if (fRequest == NULL) + return B_NO_MEMORY; + + fRequest->Stream().AddUInt(OpReadDir); + fRequest->Stream().AddUHyper(cookie[0]); + fRequest->Stream().AddUHyper(cookie[1]); + + // consider predicting this values basing on count or buffer size + fRequest->Stream().AddUInt(0x2000); + fRequest->Stream().AddUInt(0x8000); + _AttrBitmap(fRequest->Stream(), attrs, attr_count); + + fOpCount++; + + return B_OK; +} + + RPC::Call* RequestBuilder::Request() { @@ -157,3 +172,21 @@ RequestBuilder::Request() return NULL; } + +void +RequestBuilder::_AttrBitmap(XDR::WriteStream& stream, Attribute* attrs, + uint32 count) +{ + // 2 is safe in NFS4, not in NFS4.1 though + uint32 bitmap[2]; + memset(bitmap, 0, sizeof(bitmap)); + for (uint32 i = 0; i < count; i++) { + bitmap[attrs[i] / 32] |= 1 << attrs[i] % 32; + } + + uint32 bcount = bitmap[1] != 0 ? 2 : 1; + stream.AddUInt(bcount); + for (uint32 i = 0; i < bcount; i++) + stream.AddUInt(bitmap[i]); +} + diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h index 7f8b3b3ba1..838d2ae82c 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h @@ -27,10 +27,15 @@ public: status_t LookUp(const char* name); status_t PutFH(const Filehandle& fh); status_t PutRootFH(); + status_t ReadDir(uint32 count, uint64* cookie, + Attribute* attrs, uint32 attr_count); RPC::Call* Request(); private: + void _AttrBitmap(XDR::WriteStream& stream, + Attribute* attrs, uint32 count); + uint32 fOpCount; XDR::Stream::Position fOpCountPosition; 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 df9be9f1e3..f9423044a1 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -42,7 +42,8 @@ nfs4_mount(fs_volume* volume, const char* device, uint32 flags, Filesystem* fs; // hardcoded path - result = Filesystem::Mount(&fs, server, "haiku/src/add-ons/kernel"); + result = Filesystem::Mount(&fs, server, "haiku/src/add-ons/kernel", + volume->id); if (result != B_OK) { gRPCServerManager->Release(server); return result; @@ -98,7 +99,7 @@ nfs4_read_stat(fs_volume* volume, fs_vnode* vnode, struct stat* stat) static status_t nfs4_open_dir(fs_volume* volume, fs_vnode* vnode, void** _cookie) { - uint64* cookie = new(std::nothrow) uint64; + uint64* cookie = new(std::nothrow) uint64[2]; if (cookie == NULL) return B_NO_MEMORY; *_cookie = cookie; @@ -122,11 +123,21 @@ nfs4_close_dir(fs_volume* volume, fs_vnode* vnode, void* cookie) static status_t nfs4_free_dir_cookie(fs_volume* volume, fs_vnode* vnode, void* cookie) { - delete reinterpret_cast(cookie); + delete[] reinterpret_cast(cookie); return B_OK; } +static status_t +nfs4_read_dir(fs_volume* volume, fs_vnode* vnode, void* _cookie, + struct dirent* buffer, size_t bufferSize, uint32* _num) +{ + uint64* cookie = reinterpret_cast(_cookie); + Inode* inode = reinterpret_cast(vnode->private_node); + return inode->ReadDir(buffer, bufferSize, _num, cookie); +} + + status_t nfs4_init() { @@ -223,7 +234,7 @@ fs_vnode_ops gNFSv4VnodeOps = { nfs4_open_dir, nfs4_close_dir, nfs4_free_dir_cookie, - NULL, // read_dir() + nfs4_read_dir, NULL, // rewind_dir, }; From aefd79e6a737a9be08ab687c0efa33ca8dad8b4f Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Thu, 31 May 2012 18:15:13 +0200 Subject: [PATCH 025/252] nfs4: The unary & operator is not really needed --- src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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 f9423044a1..5d7b719382 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -189,7 +189,7 @@ fs_volume_ops gNFSv4VolumeOps = { fs_vnode_ops gNFSv4VnodeOps = { NULL, // lookup() NULL, // get_vnode_name() - &nfs4_put_vnode, + nfs4_put_vnode, NULL, // remove_vnode() /* VM file access */ @@ -216,7 +216,7 @@ fs_vnode_ops gNFSv4VnodeOps = { NULL, // rename() NULL, // access() - &nfs4_read_stat, + nfs4_read_stat, NULL, // write_stat() NULL, // fs_preallocate() @@ -257,7 +257,7 @@ static file_system_module_info sNFSv4ModuleInfo = { NULL, // free_identify_partition_cookie() NULL, // free_partition_content_cookie() - &nfs4_mount, + nfs4_mount, }; module_info* modules[] = { From 7bfa4fe80524316059e722a48b93e4266533f4ad Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Thu, 31 May 2012 20:13:02 +0200 Subject: [PATCH 026/252] nfs4: Add lookup() and get_vnode() hooks get_vnode() needs a way to retrieve filehandle knowing only inode number. Since NFS4 sever does not provide such services client manages its own mapping between ino_t and filehandles. --- .../kernel/file_systems/nfs4/Filehandle.h | 56 ++++++++++++++++ .../kernel/file_systems/nfs4/Filesystem.cpp | 17 +++++ .../kernel/file_systems/nfs4/Filesystem.h | 13 ++++ .../kernel/file_systems/nfs4/Inode.cpp | 65 +++++++++++++++++++ src/add-ons/kernel/file_systems/nfs4/Inode.h | 4 +- .../kernel/file_systems/nfs4/InodeIdMap.h | 51 +++++++++++++++ .../kernel/file_systems/nfs4/NFS4Defs.h | 9 +-- .../file_systems/nfs4/ReplyInterpreter.h | 8 +++ .../file_systems/nfs4/RequestBuilder.cpp | 15 +++++ .../kernel/file_systems/nfs4/RequestBuilder.h | 1 + .../file_systems/nfs4/kernel_interface.cpp | 41 +++++++++++- 11 files changed, 270 insertions(+), 10 deletions(-) create mode 100644 src/add-ons/kernel/file_systems/nfs4/Filehandle.h create mode 100644 src/add-ons/kernel/file_systems/nfs4/InodeIdMap.h diff --git a/src/add-ons/kernel/file_systems/nfs4/Filehandle.h b/src/add-ons/kernel/file_systems/nfs4/Filehandle.h new file mode 100644 index 0000000000..12baf07ef4 --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/Filehandle.h @@ -0,0 +1,56 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ +#ifndef FILEHANDLE_H +#define FILEHANDLE_H + + +#include + +#include + + +#define NFS4_FHSIZE 128 + +struct Filehandle { + uint8 fSize; + uint8 fFH[NFS4_FHSIZE]; + + inline Filehandle(); + inline Filehandle(const Filehandle& fh); + inline Filehandle& operator=(const Filehandle& fh); +}; + + +inline +Filehandle::Filehandle() + : + fSize(0) +{ +} + + +inline +Filehandle::Filehandle(const Filehandle& fh) + : + fSize(fh.fSize) +{ + memcpy(fFH, fh.fFH, fSize); +} + + +inline Filehandle& +Filehandle::operator=(const Filehandle& fh) +{ + fSize = fh.fSize; + memcpy(fFH, fh.fFH, fSize); + return *this; +} + + +#endif // FILEHANDLE_H + diff --git a/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp b/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp index b7149b08fc..c5f6e87e0e 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp @@ -123,6 +123,23 @@ Filesystem::Mount(Filesystem** pfs, RPC::Server* serv, const char* fsPath, } +status_t +Filesystem::GetInode(ino_t id, Inode** _inode) +{ + Filehandle fh; + status_t result = fInoIdMap.GetFilehandle(&fh, id); + if (result != B_OK) + return result; + + Inode* inode = new(std::nothrow)Inode(this, fh, NULL); + if (inode == NULL) + return B_NO_MEMORY; + + *_inode = inode; + return B_OK; +} + + Inode* Filesystem::CreateRootInode() { diff --git a/src/add-ons/kernel/file_systems/nfs4/Filesystem.h b/src/add-ons/kernel/file_systems/nfs4/Filesystem.h index a9386de8d2..d919c269d1 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Filesystem.h +++ b/src/add-ons/kernel/file_systems/nfs4/Filesystem.h @@ -9,11 +9,13 @@ #define FILESYSTEM_H +#include "InodeIdMap.h" #include "NFS4Defs.h" #include "RPCServer.h" class Inode; +class InodeIdMap; class Filesystem { public: @@ -21,6 +23,7 @@ public: const char* path, dev_t id); ~Filesystem(); + status_t GetInode(ino_t id, Inode** inode); Inode* CreateRootInode(); inline uint32 FHExpiryType() const; @@ -28,6 +31,7 @@ public: inline uint64 GetId(); inline dev_t DevId() const; + inline InodeIdMap* InoIdMap(); private: Filesystem(); @@ -39,6 +43,8 @@ private: vint64 fId; dev_t fDevId; + + InodeIdMap fInoIdMap; }; @@ -63,5 +69,12 @@ Filesystem::DevId() const } +inline InodeIdMap* +Filesystem::InoIdMap() +{ + return &fInoIdMap; +} + + #endif // FILESYSTEM_H diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index 329730f634..48329a1e1b 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -59,6 +59,71 @@ Inode::Inode(Filesystem* fs, const Filehandle &fh, Inode* parent) } +// filesystems that do not provide fileid are currently unsupported +// client will have to be able to create its own mapping between file names +// and made up IDs +status_t +Inode::LookUp(const char* name, ino_t* id) +{ + if (fType != NF4DIR) + return B_NOT_A_DIRECTORY; + + if (!strcmp(name, ".")) { + *id = ID(); + return B_OK; + } + + RequestBuilder req(ProcCompound); + req.PutFH(fHandle); + + if (!strcmp(name, "..")) + req.LookUpUp(); + else + req.LookUp(name); + + req.GetFH(); + + Attribute attr[] = { FATTR4_FILEID }; + req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); + + RPC::Reply *rpl; + fFilesystem->Server()->SendCall(req.Request(), &rpl); + ReplyInterpreter reply(rpl); + + status_t result = reply.PutFH(); + if (result != B_OK) + return result; + + if (!strcmp(name, "..")) + result = reply.LookUpUp(); + else + result = reply.LookUp(); + if (result != B_OK) + return result; + + Filehandle fh; + 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; + + if (count < 1 || values[0].fAttribute != FATTR4_FILEID) { + delete[] values; + return B_UNSUPPORTED; + } + *id = values[0].fData.fValue64; + delete[] values; + + fFilesystem->InoIdMap()->AddEntry(fh, *id); + return B_OK; +} + + status_t Inode::Stat(struct stat* st) { diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h b/src/add-ons/kernel/file_systems/nfs4/Inode.h index b7a8528766..c631b95889 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -26,7 +26,9 @@ public: inline ino_t ID() const; inline mode_t Type() const; + status_t LookUp(const char* name, ino_t* id); status_t Stat(struct stat* st); + status_t OpenDir(uint64* cookie); status_t ReadDir(void* buffer, uint32 size, uint32* count, uint64* cookie); @@ -44,7 +46,7 @@ private: Filehandle fHandle; Filesystem* fFilesystem; - Inode* fParent; + Inode* fParent; // this will cause trouble }; diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeIdMap.h b/src/add-ons/kernel/file_systems/nfs4/InodeIdMap.h new file mode 100644 index 0000000000..3b8bc8d54b --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/InodeIdMap.h @@ -0,0 +1,51 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ +#ifndef INODEIDMAP_H +#define INODEIDMAP_H + + +#include +#include + +#include "Filehandle.h" + + +class InodeIdMap { +public: + inline status_t AddEntry(const Filehandle& inode, + ino_t id); + inline status_t GetFilehandle(Filehandle* fh, + ino_t id); + +private: + AVLTreeMap fMap; + +}; + + +inline status_t +InodeIdMap::AddEntry(const Filehandle& inode, ino_t id) +{ + return fMap.Insert(id, inode); +} + + +inline status_t +InodeIdMap::GetFilehandle(Filehandle* fh, ino_t id) +{ + AVLTreeMap::Iterator it = fMap.Find(id); + if (!it.HasCurrent()) + return B_BAD_VALUE; + + *fh = it.Current(); + return B_OK; +} + + +#endif // INODEIDMAP_H + diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h index 3ea863096f..c755dc6870 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h @@ -13,13 +13,7 @@ #include - -#define NFS4_FHSIZE 128 - -struct Filehandle { - uint8 fSize; - uint8 fFH[NFS4_FHSIZE]; -}; +#include "Filehandle.h" enum Procedure { ProcNull = 0, @@ -31,6 +25,7 @@ enum Opcode { OpGetAttr = 9, OpGetFH = 10, OpLookUp = 15, + OpLookUpUp = 16, OpPutFH = 22, OpPutRootFH = 24, OpReadDir = 26 diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h index 8eebf24b9e..173ace3ab8 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h @@ -42,6 +42,7 @@ public: status_t GetAttr(AttrValue** attrs, uint32* count); status_t GetFH(Filehandle* fh); inline status_t LookUp(); + inline status_t LookUpUp(); inline status_t PutFH(); inline status_t PutRootFH(); status_t ReadDir(uint64* cookie, DirEntry** dirents, @@ -65,6 +66,13 @@ ReplyInterpreter::LookUp() } +inline status_t +ReplyInterpreter::LookUpUp() +{ + return _OperationError(OpLookUpUp); +} + + inline status_t ReplyInterpreter::PutFH() { diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp index 2e9bfe7f04..783999819e 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp @@ -103,6 +103,21 @@ RequestBuilder::LookUp(const char* name) } +status_t +RequestBuilder::LookUpUp() +{ + if (fProcedure != ProcCompound) + return B_BAD_VALUE; + if (fRequest == NULL) + return B_NO_MEMORY; + + fRequest->Stream().AddUInt(OpLookUpUp); + fOpCount++; + + return B_OK; +} + + status_t RequestBuilder::PutFH(const Filehandle& fh) { diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h index 838d2ae82c..e784602a85 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h @@ -25,6 +25,7 @@ public: status_t GetAttr(Attribute* attrs, uint32 count); status_t GetFH(); status_t LookUp(const char* name); + status_t LookUpUp(); status_t PutFH(const Filehandle& fh); status_t PutRootFH(); status_t ReadDir(uint32 count, uint64* cookie, 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 5d7b719382..db0e66e9a0 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -65,6 +65,26 @@ nfs4_mount(fs_volume* volume, const char* device, uint32 flags, } +static status_t +nfs4_get_vnode(fs_volume* volume, ino_t id, fs_vnode* vnode, int* _type, + uint32* _flags, bool reenter) +{ + Filesystem* fs = reinterpret_cast(volume->private_volume); + Inode* inode; + status_t result = fs->GetInode(id, &inode); + if (result != B_OK) + return result; + + vnode->ops = &gNFSv4VnodeOps; + vnode->private_node = inode; + + *_type = inode->Type(); + *_flags = 0; + + return B_OK; +} + + static status_t nfs4_unmount(fs_volume* volume) { @@ -78,6 +98,19 @@ nfs4_unmount(fs_volume* volume) } +static status_t +nfs4_lookup(fs_volume* volume, fs_vnode* dir, const char* name, ino_t* _id) +{ + Inode* inode = reinterpret_cast(dir->private_node); + status_t result = inode->LookUp(name, _id); + if (result != B_OK) + return result; + + void* ptr; + return get_vnode(volume, *_id, &ptr); +} + + static status_t nfs4_put_vnode(fs_volume* volume, fs_vnode* vnode, bool reenter) { @@ -183,11 +216,15 @@ nfs4_std_ops(int32 op, ...) fs_volume_ops gNFSv4VolumeOps = { - &nfs4_unmount + nfs4_unmount, + NULL, + NULL, + NULL, + nfs4_get_vnode, }; fs_vnode_ops gNFSv4VnodeOps = { - NULL, // lookup() + nfs4_lookup, NULL, // get_vnode_name() nfs4_put_vnode, NULL, // remove_vnode() From ed517d6c6220cb2e3357f24b98fc02fcdc6e1323 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Tue, 5 Jun 2012 14:03:53 +0200 Subject: [PATCH 027/252] nfs4: Do not store pointer to parent in inodes --- .../kernel/file_systems/nfs4/Filesystem.cpp | 4 +- .../kernel/file_systems/nfs4/Inode.cpp | 64 ++++++++++++++++--- src/add-ons/kernel/file_systems/nfs4/Inode.h | 7 +- 3 files changed, 63 insertions(+), 12 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp b/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp index c5f6e87e0e..27c27164af 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp @@ -131,7 +131,7 @@ Filesystem::GetInode(ino_t id, Inode** _inode) if (result != B_OK) return result; - Inode* inode = new(std::nothrow)Inode(this, fh, NULL); + Inode* inode = new(std::nothrow)Inode(this, fh); if (inode == NULL) return B_NO_MEMORY; @@ -143,6 +143,6 @@ Filesystem::GetInode(ino_t id, Inode** _inode) Inode* Filesystem::CreateRootInode() { - return new(std::nothrow)Inode(this, fRootFH, NULL); + return new(std::nothrow)Inode(this, fRootFH, true); } diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index 48329a1e1b..ffcdda99ea 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -18,10 +18,10 @@ // Creating Inode object from Filehandle probably is not a good idea when // filehandles are volatile. -Inode::Inode(Filesystem* fs, const Filehandle &fh, Inode* parent) +Inode::Inode(Filesystem* fs, const Filehandle &fh, bool root) : fFilesystem(fs), - fParent(parent) + fRoot(root) { memcpy(&fHandle, &fh, sizeof(fh)); @@ -65,6 +65,7 @@ Inode::Inode(Filesystem* fs, const Filehandle &fh, Inode* parent) status_t Inode::LookUp(const char* name, ino_t* id) { + dprintf("nfs4: lookup: %s\n", name); if (fType != NF4DIR) return B_NOT_A_DIRECTORY; @@ -116,10 +117,10 @@ Inode::LookUp(const char* name, ino_t* id) delete[] values; return B_UNSUPPORTED; } - *id = values[0].fData.fValue64; - delete[] values; + *id = _FileIdToInoT(values[0].fData.fValue64); + fFilesystem->InoIdMap()->AddEntry(fh, values[0].fData.fValue64); - fFilesystem->InoIdMap()->AddEntry(fh, *id); + delete[] values; return B_OK; } @@ -256,6 +257,53 @@ Inode::_FillDirEntry(struct dirent* de, ino_t id, const char* name, uint32 pos, } +status_t +Inode::_ReadDirUp(struct dirent* de, uint32 pos, uint32 size) +{ + RequestBuilder req(ProcCompound); + req.PutFH(fHandle); + req.LookUpUp(); + req.GetFH(); + Attribute attr[] = { FATTR4_FILEID }; + req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); + + RPC::Reply *rpl; + fFilesystem->Server()->SendCall(req.Request(), &rpl); + ReplyInterpreter reply(rpl); + + status_t result; + result = reply.PutFH(); + if (result != B_OK) + return result; + + result = reply.LookUpUp(); + if (result != B_OK) + return result; + + Filehandle fh; + 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[0].fAttribute != FATTR4_FILEID) { + // Server does not provide fileid. We need to make something up. + fileId = fFilesystem->GetId(); + } else + fileId = values[0].fData.fValue64; + + fFilesystem->InoIdMap()->AddEntry(fh, fileId); + + return _FillDirEntry(de, _FileIdToInoT(fileId), "..", pos, size); +} + + status_t Inode::ReadDir(void* _buffer, uint32 size, uint32* _count, uint64* cookie) { @@ -279,10 +327,10 @@ Inode::ReadDir(void* _buffer, uint32 size, uint32* _count, uint64* cookie) if (cookie[0] == 0 && cookie[1] == 1 && count < *_count) { struct dirent* de = reinterpret_cast(buffer + pos); - if (fParent != NULL) - _FillDirEntry(de, fParent->fFileId, "..", pos, size); + if (!fRoot) + _ReadDirUp(de, pos, size); else - _FillDirEntry(de, fFileId, "..", pos, size); + _FillDirEntry(de, _FileIdToInoT(fFileId), "..", pos, size); pos += de->d_reclen; count++; diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h b/src/add-ons/kernel/file_systems/nfs4/Inode.h index c631b95889..0245e91a79 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -21,7 +21,7 @@ class Inode { public: Inode(Filesystem* fs, const Filehandle &fh, - Inode* parent); + bool root = false); inline ino_t ID() const; inline mode_t Type() const; @@ -38,6 +38,8 @@ private: uint64* cookie, bool* eof); 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); static inline ino_t _FileIdToInoT(uint64 fileid); @@ -46,7 +48,8 @@ private: Filehandle fHandle; Filesystem* fFilesystem; - Inode* fParent; // this will cause trouble + + bool fRoot; }; From f29ac4afd944ae3c279fae69ad325a3976b5fa82 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Tue, 5 Jun 2012 14:30:57 +0200 Subject: [PATCH 028/252] nfs4: readdir() should not read more than requested Additionally, file attribute decoding checks more strictly whether received data are sane. --- src/add-ons/kernel/file_systems/nfs4/Inode.cpp | 7 +++---- src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h | 3 ++- src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp | 8 ++++++++ 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index ffcdda99ea..fa9091b464 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -65,7 +65,6 @@ Inode::Inode(Filesystem* fs, const Filehandle &fh, bool root) status_t Inode::LookUp(const char* name, ino_t* id) { - dprintf("nfs4: lookup: %s\n", name); if (fType != NF4DIR) return B_NOT_A_DIRECTORY; @@ -338,7 +337,7 @@ Inode::ReadDir(void* _buffer, uint32 size, uint32* _count, uint64* cookie) } while (count < *_count && !eof) { - this_count = *_count; + this_count = *_count - count; DirEntry* dirents; status_t result = _ReadDirOnce(&dirents, &this_count, cookie, &eof); @@ -346,7 +345,7 @@ Inode::ReadDir(void* _buffer, uint32 size, uint32* _count, uint64* cookie) return result; uint32 i; - for (i = 0; i < this_count; i++) { + for (i = 0; i < min_c(this_count, *_count - count); i++) { struct dirent* de = reinterpret_cast(buffer + pos); ino_t id; @@ -371,7 +370,7 @@ Inode::ReadDir(void* _buffer, uint32 size, uint32* _count, uint64* cookie) return B_BUFFER_OVERFLOW; *_count = count; - + return B_OK; } diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h index c755dc6870..860a32ff91 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h @@ -99,7 +99,8 @@ enum Attribute { FATTR4_TIME_METADATA = 52, FATTR4_TIME_MODIFY = 53, FATTR4_TIME_MODIFY_SET = 54, - FATTR4_MOUNTED_ON_FILEID = 55 + FATTR4_MOUNTED_ON_FILEID = 55, + FATTR4_MAXIMUM_ATTR_ID }; enum FileType { diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp index b0137b01f9..77d999ee03 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp @@ -155,6 +155,7 @@ ReplyInterpreter::ReadDir(uint64* cookie, DirEntry** dirents, uint32* _count, return B_OK; } + status_t ReplyInterpreter::_DecodeAttrs(XDR::ReadStream& str, AttrValue** attrs, uint32* count) @@ -170,6 +171,13 @@ ReplyInterpreter::_DecodeAttrs(XDR::ReadStream& str, AttrValue** attrs, attr_count += sCountBits(bitmap[i]); } + if (attr_count == 0) { + *attrs = NULL; + *count = 0; + return B_OK; + } else if (attr_count > FATTR4_MAXIMUM_ATTR_ID) + return B_BAD_VALUE; + uint32 size; const void* ptr = str.GetOpaque(&size); XDR::ReadStream stream(const_cast(ptr), size); From e8845bd5b7d8a24c9ba26a38c556222149ad8553 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Tue, 5 Jun 2012 14:35:30 +0200 Subject: [PATCH 029/252] nfs4: Add rewind_dir() hook --- .../kernel/file_systems/nfs4/kernel_interface.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) 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 db0e66e9a0..023c56735c 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -171,6 +171,16 @@ nfs4_read_dir(fs_volume* volume, fs_vnode* vnode, void* _cookie, } +static status_t +nfs4_rewind_dir(fs_volume* volume, fs_vnode* vnode, void* _cookie) +{ + uint64* cookie = reinterpret_cast(_cookie); + cookie[0] = 0; + cookie[1] = 2; + + return B_OK; +} + status_t nfs4_init() { @@ -272,7 +282,7 @@ fs_vnode_ops gNFSv4VnodeOps = { nfs4_close_dir, nfs4_free_dir_cookie, nfs4_read_dir, - NULL, // rewind_dir, + nfs4_rewind_dir, }; static file_system_module_info sNFSv4ModuleInfo = { From 87c6b83293724346b8b2899fb288fd28d200a5da Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Tue, 5 Jun 2012 18:35:41 +0200 Subject: [PATCH 030/252] nfs4: Inodes should know their name and parent's filehandle --- .../kernel/file_systems/nfs4/Filehandle.h | 54 +++++++++++++++++++ .../kernel/file_systems/nfs4/Filesystem.cpp | 15 ++++-- .../kernel/file_systems/nfs4/Inode.cpp | 26 +++++---- src/add-ons/kernel/file_systems/nfs4/Inode.h | 7 +-- .../kernel/file_systems/nfs4/InodeIdMap.h | 27 ++++++---- .../file_systems/nfs4/kernel_interface.cpp | 9 +++- 6 files changed, 109 insertions(+), 29 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Filehandle.h b/src/add-ons/kernel/file_systems/nfs4/Filehandle.h index 12baf07ef4..cdc149988e 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Filehandle.h +++ b/src/add-ons/kernel/file_systems/nfs4/Filehandle.h @@ -9,6 +9,7 @@ #define FILEHANDLE_H +#include #include #include @@ -26,6 +27,24 @@ struct Filehandle { }; +// Complete information needed to identify a file in any situation. +// Unfortunately just a filehandle is not enough even when they are persistent +// since OPEN requires both parent filehandle and file name (just like LOOKUP). +struct FileInfo { + Filehandle fFH; + + Filehandle fParent; + const char* fName; + + // ... full path may be needed if filehandles are volatile + + inline FileInfo(); + inline ~FileInfo(); + inline FileInfo(const FileInfo& fi); + inline FileInfo& operator=(const FileInfo& fi); +}; + + inline Filehandle::Filehandle() : @@ -52,5 +71,40 @@ Filehandle::operator=(const Filehandle& fh) } +inline +FileInfo::FileInfo() + : + fName(NULL) +{ +} + + +inline +FileInfo::~FileInfo() +{ + free(const_cast(fName)); +} + + +inline +FileInfo::FileInfo(const FileInfo& fi) + : + fFH(fi.fFH), + fParent(fi.fParent), + fName(strdup(fi.fName)) +{ +} + + +inline FileInfo& +FileInfo::operator=(const FileInfo& fi) +{ + fFH = fi.fFH; + fParent = fi.fParent; + fName = strdup(fi.fName); + return *this; +} + + #endif // FILEHANDLE_H diff --git a/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp b/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp index 27c27164af..aa9748c42c 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp @@ -126,12 +126,15 @@ Filesystem::Mount(Filesystem** pfs, RPC::Server* serv, const char* fsPath, status_t Filesystem::GetInode(ino_t id, Inode** _inode) { - Filehandle fh; - status_t result = fInoIdMap.GetFilehandle(&fh, id); + FileInfo fi; + status_t result = fInoIdMap.GetFileInfo(&fi, id); + if (result == B_ENTRY_NOT_FOUND) + dprintf("NFS4: unknown inode: %llu\n", id); + if (result != B_OK) return result; - Inode* inode = new(std::nothrow)Inode(this, fh); + Inode* inode = new(std::nothrow)Inode(this, fi); if (inode == NULL) return B_NO_MEMORY; @@ -143,6 +146,10 @@ Filesystem::GetInode(ino_t id, Inode** _inode) Inode* Filesystem::CreateRootInode() { - return new(std::nothrow)Inode(this, fRootFH, true); + FileInfo fi; + fi.fFH = fRootFH; + fi.fParent = fRootFH; + fi.fName = strdup("/"); + return new(std::nothrow)Inode(this, fi); } diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index fa9091b464..b69e177a84 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -18,15 +18,15 @@ // Creating Inode object from Filehandle probably is not a good idea when // filehandles are volatile. -Inode::Inode(Filesystem* fs, const Filehandle &fh, bool root) +Inode::Inode(Filesystem* fs, const FileInfo &fi) : + fHandle(fi.fFH), fFilesystem(fs), - fRoot(root) + fParentFH(fi.fParent), + fName(strdup(fi.fName)) { - memcpy(&fHandle, &fh, sizeof(fh)); - RequestBuilder req(ProcCompound); - req.PutFH(fh); + req.PutFH(fHandle); Attribute attr[] = { FATTR4_TYPE, FATTR4_FILEID }; req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); @@ -59,6 +59,12 @@ Inode::Inode(Filesystem* fs, const Filehandle &fh, bool root) } +Inode::~Inode() +{ + free(const_cast(fName)); +} + + // filesystems that do not provide fileid are currently unsupported // client will have to be able to create its own mapping between file names // and made up IDs @@ -116,10 +122,12 @@ Inode::LookUp(const char* name, ino_t* id) delete[] values; return B_UNSUPPORTED; } - *id = _FileIdToInoT(values[0].fData.fValue64); - fFilesystem->InoIdMap()->AddEntry(fh, values[0].fData.fValue64); + *id = _FileIdToInoT(values[0].fData.fValue64); delete[] values; + + fFilesystem->InoIdMap()->AddEntry(fh, fHandle, name, *id); + return B_OK; } @@ -296,8 +304,6 @@ Inode::_ReadDirUp(struct dirent* de, uint32 pos, uint32 size) fileId = fFilesystem->GetId(); } else fileId = values[0].fData.fValue64; - - fFilesystem->InoIdMap()->AddEntry(fh, fileId); return _FillDirEntry(de, _FileIdToInoT(fileId), "..", pos, size); } @@ -326,7 +332,7 @@ Inode::ReadDir(void* _buffer, uint32 size, uint32* _count, uint64* cookie) if (cookie[0] == 0 && cookie[1] == 1 && count < *_count) { struct dirent* de = reinterpret_cast(buffer + pos); - if (!fRoot) + if (strcmp(fName, "/")) _ReadDirUp(de, pos, size); else _FillDirEntry(de, _FileIdToInoT(fFileId), "..", pos, size); diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h b/src/add-ons/kernel/file_systems/nfs4/Inode.h index 0245e91a79..b21f790f9f 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -20,8 +20,8 @@ class Inode { public: - Inode(Filesystem* fs, const Filehandle &fh, - bool root = false); + Inode(Filesystem* fs, const FileInfo& fi); + ~Inode(); inline ino_t ID() const; inline mode_t Type() const; @@ -49,7 +49,8 @@ private: Filehandle fHandle; Filesystem* fFilesystem; - bool fRoot; + Filehandle fParentFH; + const char* fName; }; diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeIdMap.h b/src/add-ons/kernel/file_systems/nfs4/InodeIdMap.h index 3b8bc8d54b..887ab2f98e 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeIdMap.h +++ b/src/add-ons/kernel/file_systems/nfs4/InodeIdMap.h @@ -17,32 +17,37 @@ class InodeIdMap { public: - inline status_t AddEntry(const Filehandle& inode, - ino_t id); - inline status_t GetFilehandle(Filehandle* fh, - ino_t id); + inline status_t AddEntry(const Filehandle& fh, + const Filehandle& parent, + const char* name, ino_t id); + inline status_t GetFileInfo(FileInfo* fi, ino_t id); private: - AVLTreeMap fMap; + AVLTreeMap fMap; }; inline status_t -InodeIdMap::AddEntry(const Filehandle& inode, ino_t id) +InodeIdMap::AddEntry(const Filehandle& fh, const Filehandle& parent, + const char* name, ino_t id) { - return fMap.Insert(id, inode); + FileInfo fi; + fi.fFH = fh; + fi.fParent = parent; + fi.fName = strdup(name); + return fMap.Insert(id, fi); } inline status_t -InodeIdMap::GetFilehandle(Filehandle* fh, ino_t id) +InodeIdMap::GetFileInfo(FileInfo* fi, ino_t id) { - AVLTreeMap::Iterator it = fMap.Find(id); + AVLTreeMap::Iterator it = fMap.Find(id); if (!it.HasCurrent()) - return B_BAD_VALUE; + return B_ENTRY_NOT_FOUND; - *fh = it.Current(); + *fi = it.Current(); return B_OK; } 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 023c56735c..085b0b4a1e 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -129,6 +129,13 @@ nfs4_read_stat(fs_volume* volume, fs_vnode* vnode, struct stat* stat) } +static status_t +nfs4_open(fs_volume* volume, fs_vnode* vnode, int openMode, void** _cookie) +{ + return B_ERROR; +} + + static status_t nfs4_open_dir(fs_volume* volume, fs_vnode* vnode, void** _cookie) { @@ -269,7 +276,7 @@ fs_vnode_ops gNFSv4VnodeOps = { /* file operations */ NULL, // create() - NULL, // open() + nfs4_open, NULL, // close() NULL, // free_cookie() NULL, // read() From 96b7b14a96e08e329b6e439752a44df963e7b43c Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Tue, 5 Jun 2012 19:01:25 +0200 Subject: [PATCH 031/252] nfs4: Add get_vnode_name hook --- src/add-ons/kernel/file_systems/nfs4/Inode.h | 8 ++++++++ .../kernel/file_systems/nfs4/kernel_interface.cpp | 12 +++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h b/src/add-ons/kernel/file_systems/nfs4/Inode.h index b21f790f9f..4d85cf9938 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -25,6 +25,7 @@ public: inline ino_t ID() const; inline mode_t Type() const; + inline const char* Name() const; status_t LookUp(const char* name, ino_t* id); status_t Stat(struct stat* st); @@ -79,5 +80,12 @@ Inode::Type() const } +inline const char* +Inode::Name() const +{ + return fName; +} + + #endif // INODE_H 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 085b0b4a1e..2872647b9d 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -111,6 +111,16 @@ nfs4_lookup(fs_volume* volume, fs_vnode* dir, const char* name, ino_t* _id) } +static status_t +nfs4_get_vnode_name(fs_volume* volume, fs_vnode* vnode, char* buffer, + size_t bufferSize) +{ + Inode* inode = reinterpret_cast(vnode->private_node); + strncpy(buffer, inode->Name(), bufferSize); + return B_OK; +} + + static status_t nfs4_put_vnode(fs_volume* volume, fs_vnode* vnode, bool reenter) { @@ -242,7 +252,7 @@ fs_volume_ops gNFSv4VolumeOps = { fs_vnode_ops gNFSv4VnodeOps = { nfs4_lookup, - NULL, // get_vnode_name() + nfs4_get_vnode_name, nfs4_put_vnode, NULL, // remove_vnode() From 8d513ebcb5b3faa44556497905ceb0041737349a Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Tue, 5 Jun 2012 20:41:19 +0200 Subject: [PATCH 032/252] nfs4: Fix FileInfo operator= memory leak --- src/add-ons/kernel/file_systems/nfs4/Filehandle.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/add-ons/kernel/file_systems/nfs4/Filehandle.h b/src/add-ons/kernel/file_systems/nfs4/Filehandle.h index cdc149988e..3d66aa6027 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Filehandle.h +++ b/src/add-ons/kernel/file_systems/nfs4/Filehandle.h @@ -101,6 +101,8 @@ FileInfo::operator=(const FileInfo& fi) { fFH = fi.fFH; fParent = fi.fParent; + + free(const_cast(fName)); fName = strdup(fi.fName); return *this; } From 2a292557d4bffd34841c3db2ee1095a1a51f0274 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Tue, 5 Jun 2012 22:30:23 +0200 Subject: [PATCH 033/252] nfs4: Add open() hook --- .../kernel/file_systems/nfs4/Connection.cpp | 27 +++++ .../kernel/file_systems/nfs4/Connection.h | 4 + .../kernel/file_systems/nfs4/Inode.cpp | 64 ++++++++++ src/add-ons/kernel/file_systems/nfs4/Inode.h | 8 ++ .../kernel/file_systems/nfs4/NFS4Defs.h | 35 ++++-- .../kernel/file_systems/nfs4/RPCServer.h | 12 ++ .../file_systems/nfs4/ReplyInterpreter.cpp | 70 ++++++++++- .../file_systems/nfs4/ReplyInterpreter.h | 11 ++ .../file_systems/nfs4/RequestBuilder.cpp | 113 ++++++++++++++++++ .../kernel/file_systems/nfs4/RequestBuilder.h | 7 ++ .../file_systems/nfs4/kernel_interface.cpp | 12 +- 11 files changed, 350 insertions(+), 13 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Connection.cpp b/src/add-ons/kernel/file_systems/nfs4/Connection.cpp index c1b7e89f75..0143f79bc6 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Connection.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Connection.cpp @@ -42,6 +42,16 @@ ServerAddress::operator<(const ServerAddress& x) } +ServerAddress& +ServerAddress::operator=(const ServerAddress& x) +{ + fAddress = x.fAddress; + fPort = x.fPort; + fProtocol = x.fProtocol; + return *this; +} + + Connection::Connection(const sockaddr_in& addr, Transport proto, bool markers) : fSock(-1), @@ -61,6 +71,23 @@ Connection::~Connection() } +status_t +Connection::GetLocalID(ServerAddress* addr) +{ + struct sockaddr_in saddr; + socklen_t slen = sizeof(addr); + status_t result = kgetsockname(fSock, (struct sockaddr*)&saddr, &slen); + if (result != B_OK) + return result; + + addr->fProtocol = fProtocol; + addr->fPort = ntohs(saddr.sin_port); + addr->fAddress = ntohl(saddr.sin_addr.s_addr); + + return B_OK; +} + + status_t Connection::_SendStream(const void* buffer, uint32 size) { diff --git a/src/add-ons/kernel/file_systems/nfs4/Connection.h b/src/add-ons/kernel/file_systems/nfs4/Connection.h index 11029c3230..041c5deda2 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Connection.h +++ b/src/add-ons/kernel/file_systems/nfs4/Connection.h @@ -27,6 +27,8 @@ struct ServerAddress { bool operator==(const ServerAddress& x); bool operator<(const ServerAddress& x); + + ServerAddress& operator=(const ServerAddress& x); }; class Connection { @@ -38,6 +40,8 @@ public: inline status_t Send(const void* buffer, uint32 size); inline status_t Receive(void** buffer, uint32* size); + status_t GetLocalID(ServerAddress* addr); + status_t Reconnect(); void Disconnect(); diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index b69e177a84..134a69fb7c 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -185,6 +185,70 @@ Inode::Stat(struct stat* st) } +status_t +Inode::Open(int mode, OpenFileCookie* cookie) +{ + cookie->fSeq = 0; + + RequestBuilder req_setid(ProcCompound); + req_setid.SetClientID(fFilesystem->Server()); + + RPC::Reply *rpl; + fFilesystem->Server()->SendCall(req_setid.Request(), &rpl); + ReplyInterpreter setid(rpl); + + uint64 id, ver; + status_t result = setid.SetClientID(&id, &ver); + if (result != B_OK) + return result; + + RequestBuilder req_conf(ProcCompound); + req_conf.SetClientIDConfirm(id, ver); + + fFilesystem->Server()->SendCall(req_conf.Request(), &rpl); + ReplyInterpreter conf(rpl); + + result = conf.SetClientIDConfirm(); + if (result != B_OK) + return result; + + RequestBuilder req(ProcCompound); + req.PutFH(fParentFH); + req.Open(cookie->fSeq, OPEN4_SHARE_ACCESS_READ, id, OPEN4_NOCREATE, fName); + cookie->fSeq++; + fFilesystem->Server()->SendCall(req.Request(), &rpl); + ReplyInterpreter reply(rpl); + + result = reply.PutFH(); + if (result != B_OK) + return result; + + bool confirm; + result = reply.Open(cookie->fStateId, &cookie->fStateSeq, &confirm); + if (result != B_OK) + return result; + + if (confirm) { + RequestBuilder req(ProcCompound); + req.PutFH(fHandle); + req.OpenConfirm(cookie->fSeq, cookie->fStateId, cookie->fStateSeq); + cookie->fSeq++; + fFilesystem->Server()->SendCall(req.Request(), &rpl); + ReplyInterpreter reply(rpl); + + result = reply.PutFH(); + if (result != B_OK) + return result; + + result = reply.OpenConfirm(&cookie->fStateSeq); + if (result != B_OK) + return result; + } + + return B_OK; +} + + status_t Inode::OpenDir(uint64* cookie) { diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h b/src/add-ons/kernel/file_systems/nfs4/Inode.h index 4d85cf9938..769a71a6a3 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -18,6 +18,12 @@ #include "ReplyInterpreter.h" +struct OpenFileCookie { + uint32 fStateId[3]; + uint32 fStateSeq; + uint32 fSeq; +}; + class Inode { public: Inode(Filesystem* fs, const FileInfo& fi); @@ -30,6 +36,8 @@ public: status_t LookUp(const char* name, ino_t* id); status_t Stat(struct stat* st); + status_t Open(int mode, OpenFileCookie* cookie); + status_t OpenDir(uint64* cookie); status_t ReadDir(void* buffer, uint32 size, uint32* count, uint64* cookie); diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h index 860a32ff91..f53e0fd8cb 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h @@ -21,14 +21,18 @@ enum Procedure { }; enum Opcode { - OpAccess = 3, - OpGetAttr = 9, - OpGetFH = 10, - OpLookUp = 15, - OpLookUpUp = 16, - OpPutFH = 22, - OpPutRootFH = 24, - OpReadDir = 26 + OpAccess = 3, + OpGetAttr = 9, + OpGetFH = 10, + OpLookUp = 15, + OpLookUpUp = 16, + OpOpen = 18, + OpOpenConfirm = 20, + OpPutFH = 22, + OpPutRootFH = 24, + OpReadDir = 26, + OpSetClientID = 35, + OpSetClientIDConfirm = 36 }; enum Access { @@ -128,6 +132,21 @@ enum FileHandleExpiryType { FH4_VOL_RENAME = 0x08 }; +enum OpenAccess { + OPEN4_SHARE_ACCESS_READ = 1, + OPEN4_SHARE_ACCESS_WRITE = 2 +}; + +enum OpenCreate { + OPEN4_NOCREATE = 0, + OPEN4_CREATE = 1 +}; + +enum OpenFlags { + OPEN4_RESULT_CONFIRM = 2, + OPEN4_RESULT_LOCKTYPE_POSIX = 4 +}; + enum Errors { NFS4_OK = 0, NFS4ERR_PERM = 1, diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCServer.h b/src/add-ons/kernel/file_systems/nfs4/RPCServer.h index 5a7d3d0a46..13cf8b2256 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RPCServer.h +++ b/src/add-ons/kernel/file_systems/nfs4/RPCServer.h @@ -53,6 +53,7 @@ public: status_t Repair(); inline const ServerAddress& ID() const; + inline ServerAddress LocalID() const; private: inline uint32 _GetXID(); @@ -80,6 +81,17 @@ Server::ID() const return *fAddress; } + +inline ServerAddress +Server::LocalID() const +{ + ServerAddress addr; + memset(&addr, 0, sizeof(addr)); + fConnection->GetLocalID(&addr); + return addr; +} + + struct ServerNode { ServerAddress fID; Server* fServer; diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp index 77d999ee03..dac46ce247 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp @@ -61,7 +61,7 @@ ReplyInterpreter::Access(uint32* supported, uint32* allowed) if (allowed != NULL) *allowed = allow; - return B_OK; + return fReply->Stream().IsEOF() ? B_BAD_VALUE : B_OK; } @@ -112,7 +112,55 @@ ReplyInterpreter::GetFH(Filehandle* fh) memcpy(fh->fFH, ptr, size); } - return B_OK; + return fReply->Stream().IsEOF() ? B_BAD_VALUE : B_OK; +} + + +status_t +ReplyInterpreter::Open(uint32* id, uint32* seq, bool* confirm) +{ + status_t res = _OperationError(OpOpen); + if (res != B_OK) + return res; + + *seq = fReply->Stream().GetUInt(); + id[0] = fReply->Stream().GetUInt(); + id[1] = fReply->Stream().GetUInt(); + id[2] = fReply->Stream().GetUInt(); + + // change info + fReply->Stream().GetBoolean(); + fReply->Stream().GetUHyper(); + fReply->Stream().GetUHyper(); + + uint32 flags = fReply->Stream().GetUInt(); + *confirm = (flags & OPEN4_RESULT_CONFIRM) == OPEN4_RESULT_CONFIRM; + + // attrmask + uint32 bcount = fReply->Stream().GetUInt(); + for (uint32 i = 0; i < bcount; i++) + fReply->Stream().GetUInt(); + + // delegation info + fReply->Stream().GetUInt(); + + return fReply->Stream().IsEOF() ? B_BAD_VALUE : B_OK; +} + + +status_t +ReplyInterpreter::OpenConfirm(uint32* stateSeq) +{ + status_t res = _OperationError(OpOpenConfirm); + if (res != B_OK) + return res; + + *stateSeq = fReply->Stream().GetUInt(); + fReply->Stream().GetUInt(); + fReply->Stream().GetUInt(); + fReply->Stream().GetUInt(); + + return fReply->Stream().IsEOF() ? B_BAD_VALUE : B_OK; } @@ -152,7 +200,21 @@ ReplyInterpreter::ReadDir(uint64* cookie, DirEntry** dirents, uint32* _count, *_count = count; *dirents = entries; - return B_OK; + return fReply->Stream().IsEOF() ? B_BAD_VALUE : B_OK; +} + + +status_t +ReplyInterpreter::SetClientID(uint64* clientid, uint64* verifier) +{ + status_t res = _OperationError(OpSetClientID); + if (res != B_OK) + return res; + + *clientid = fReply->Stream().GetUHyper(); + *verifier = fReply->Stream().GetUHyper(); + + return fReply->Stream().IsEOF() ? B_BAD_VALUE : B_OK; } @@ -230,7 +292,7 @@ ReplyInterpreter::_DecodeAttrs(XDR::ReadStream& str, AttrValue** attrs, *count = attr_count; *attrs = values; - return B_OK; + return str.IsEOF() ? B_BAD_VALUE : B_OK; } diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h index 173ace3ab8..9a6f4188d4 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h @@ -43,10 +43,14 @@ public: status_t GetFH(Filehandle* fh); inline status_t LookUp(); inline status_t LookUpUp(); + status_t Open(uint32* id, uint32* seq, bool* confirm); + status_t OpenConfirm(uint32* stateSeq); inline status_t PutFH(); inline status_t PutRootFH(); status_t ReadDir(uint64* cookie, DirEntry** dirents, uint32* count, bool* eof); + status_t SetClientID(uint64* clientid, uint64* verifier); + inline status_t SetClientIDConfirm(); private: status_t _DecodeAttrs(XDR::ReadStream& stream, AttrValue** attrs, @@ -87,5 +91,12 @@ ReplyInterpreter::PutRootFH() } +inline status_t +ReplyInterpreter::SetClientIDConfirm() +{ + return _OperationError(OpSetClientIDConfirm); +} + + #endif // REPLYINTERPRETER_H diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp index 783999819e..3ce7f2c98b 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp @@ -118,6 +118,62 @@ RequestBuilder::LookUpUp() } +status_t +RequestBuilder::Open(uint32 seq, uint32 access, uint64 id, OpenCreate oc, + const char* name) +{ + if (fProcedure != ProcCompound) + return B_BAD_VALUE; + if (fRequest == NULL) + return B_NO_MEMORY; + + fRequest->Stream().AddUInt(OpOpen); + fRequest->Stream().AddUInt(seq); + fRequest->Stream().AddUInt(access); + fRequest->Stream().AddUInt(0); // deny none + fRequest->Stream().AddUHyper(id); + + char owner[128]; + int pos = 0; + *(uint32*)(owner + pos) = time(NULL); + pos += sizeof(uint32); + + *(uint32*)(owner + pos) = find_thread(NULL); + pos += sizeof(uint32); + + fRequest->Stream().AddOpaque(owner, pos); + + fRequest->Stream().AddUInt(oc); + fRequest->Stream().AddUInt(0); // claim null + fRequest->Stream().AddString(name, strlen(name)); + + fOpCount++; + + return B_OK; +} + + +status_t +RequestBuilder::OpenConfirm(uint32 seq, const uint32* id, uint32 stateSeq) +{ + if (fProcedure != ProcCompound) + return B_BAD_VALUE; + if (fRequest == NULL) + return B_NO_MEMORY; + + fRequest->Stream().AddUInt(OpOpenConfirm); + fRequest->Stream().AddUInt(stateSeq); + fRequest->Stream().AddUInt(id[0]); + fRequest->Stream().AddUInt(id[1]); + fRequest->Stream().AddUInt(id[2]); + fRequest->Stream().AddUInt(seq); + + fOpCount++; + + return B_OK; +} + + status_t RequestBuilder::PutFH(const Filehandle& fh) { @@ -175,6 +231,63 @@ RequestBuilder::ReadDir(uint32 count, uint64* cookie, Attribute* attrs, } +status_t +RequestBuilder::SetClientID(const RPC::Server* serv) +{ + if (fProcedure != ProcCompound) + return B_BAD_VALUE; + if (fRequest == NULL) + return B_NO_MEMORY; + + fRequest->Stream().AddUInt(OpSetClientID); + uint64 verifier = rand(); + verifier = verifier << 32 | rand(); + fRequest->Stream().AddUHyper(verifier); + + char id[128] = "HAIKU:kernel:"; + int pos = strlen(id); + *(uint32*)(id + pos) = serv->ID().fAddress; + pos += sizeof(uint32); + *(uint16*)(id + pos) = serv->ID().fPort; + pos += sizeof(uint16); + *(uint16*)(id + pos) = serv->ID().fProtocol; + pos += sizeof(uint16); + + *(uint32*)(id + pos) = serv->LocalID().fAddress; + pos += sizeof(uint32); + + fRequest->Stream().AddOpaque(id, pos); + + // Callbacks are currently not supported + fRequest->Stream().AddUInt(0); + fRequest->Stream().AddOpaque(NULL, 0); + fRequest->Stream().AddOpaque(NULL, 0); + fRequest->Stream().AddUInt(0); + + fOpCount++; + + return B_OK; +} + + +status_t +RequestBuilder::SetClientIDConfirm(uint64 id, uint64 ver) +{ + if (fProcedure != ProcCompound) + return B_BAD_VALUE; + if (fRequest == NULL) + return B_NO_MEMORY; + + fRequest->Stream().AddUInt(OpSetClientIDConfirm); + fRequest->Stream().AddUHyper(id); + fRequest->Stream().AddUHyper(ver); + + fOpCount++; + + return B_OK; +} + + RPC::Call* RequestBuilder::Request() { diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h index e784602a85..e3b5d301eb 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h @@ -13,6 +13,7 @@ #include "NFS4Defs.h" #include "RPCCall.h" +#include "RPCServer.h" #include "XDR.h" @@ -26,10 +27,16 @@ public: status_t GetFH(); status_t LookUp(const char* name); status_t LookUpUp(); + status_t Open(uint32 seq, uint32 access, uint64 id, + OpenCreate oc, const char* name); + status_t OpenConfirm(uint32 seq, const uint32* id, + uint32 stateSeq); status_t PutFH(const Filehandle& fh); status_t PutRootFH(); status_t ReadDir(uint32 count, uint64* cookie, Attribute* attrs, uint32 attr_count); + status_t SetClientID(const RPC::Server* serv); + status_t SetClientIDConfirm(uint64 id, uint64 ver); RPC::Call* Request(); 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 2872647b9d..d9d3e355a1 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -142,7 +142,17 @@ nfs4_read_stat(fs_volume* volume, fs_vnode* vnode, struct stat* stat) static status_t nfs4_open(fs_volume* volume, fs_vnode* vnode, int openMode, void** _cookie) { - return B_ERROR; + OpenFileCookie* cookie = new OpenFileCookie; + if (cookie == NULL) + return B_NO_MEMORY; + *_cookie = cookie; + + Inode* inode = reinterpret_cast(vnode->private_node); + status_t result = inode->Open(openMode, cookie); + if (result != B_OK) + delete cookie; + + return result; } From 2f2e57d03557301f838496118884de305d6abde8 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Tue, 5 Jun 2012 22:56:33 +0200 Subject: [PATCH 034/252] nfs4: Add read() hook --- .../kernel/file_systems/nfs4/Inode.cpp | 35 +++++++++++++++++++ src/add-ons/kernel/file_systems/nfs4/Inode.h | 2 ++ .../kernel/file_systems/nfs4/NFS4Defs.h | 1 + .../file_systems/nfs4/ReplyInterpreter.cpp | 15 ++++++++ .../file_systems/nfs4/ReplyInterpreter.h | 1 + .../file_systems/nfs4/RequestBuilder.cpp | 22 ++++++++++++ .../kernel/file_systems/nfs4/RequestBuilder.h | 2 ++ .../file_systems/nfs4/kernel_interface.cpp | 13 ++++++- 8 files changed, 90 insertions(+), 1 deletion(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index 134a69fb7c..e4f855ddda 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -249,6 +249,41 @@ Inode::Open(int mode, OpenFileCookie* cookie) } +status_t +Inode::Read(OpenFileCookie* cookie, off_t pos, void* buffer, size_t* _length) +{ + bool eof = false; + uint32 size = 0; + uint32 len = 0; + + while (size < *_length && !eof) { + RequestBuilder req(ProcCompound); + req.PutFH(fHandle); + req.Read(cookie->fStateId, cookie->fStateSeq, pos + size, + *_length - size); + + RPC::Reply *rpl; + fFilesystem->Server()->SendCall(req.Request(), &rpl); + ReplyInterpreter reply(rpl); + + status_t result; + result = reply.PutFH(); + if (result != B_OK) + return result; + + result = reply.Read(reinterpret_cast(buffer) + size, &len, &eof); + if (result != B_OK) + return result; + + size += len; + } + + *_length = size; + + return B_OK; +} + + status_t Inode::OpenDir(uint64* cookie) { diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h b/src/add-ons/kernel/file_systems/nfs4/Inode.h index 769a71a6a3..c75e197620 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -37,6 +37,8 @@ public: status_t Stat(struct stat* st); status_t Open(int mode, OpenFileCookie* cookie); + status_t Read(OpenFileCookie* cookie, off_t pos, + void* buffer, size_t* length); status_t OpenDir(uint64* cookie); status_t ReadDir(void* buffer, uint32 size, diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h index f53e0fd8cb..d9648a1cc5 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h @@ -30,6 +30,7 @@ enum Opcode { OpOpenConfirm = 20, OpPutFH = 22, OpPutRootFH = 24, + OpRead = 25, OpReadDir = 26, OpSetClientID = 35, OpSetClientIDConfirm = 36 diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp index dac46ce247..1c158ee38c 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp @@ -164,6 +164,21 @@ ReplyInterpreter::OpenConfirm(uint32* stateSeq) } +status_t +ReplyInterpreter::Read(void* buffer, uint32* size, bool* eof) +{ + status_t res = _OperationError(OpRead); + if (res != B_OK) + return res; + + *eof = fReply->Stream().GetBoolean(); + const void* ptr = fReply->Stream().GetOpaque(size); + memcpy(buffer, ptr, *size); + + return fReply->Stream().IsEOF() ? B_BAD_VALUE : B_OK; +} + + status_t ReplyInterpreter::ReadDir(uint64* cookie, DirEntry** dirents, uint32* _count, bool* eof) diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h index 9a6f4188d4..c3d5395349 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h @@ -47,6 +47,7 @@ public: status_t OpenConfirm(uint32* stateSeq); inline status_t PutFH(); inline status_t PutRootFH(); + status_t Read(void* buffer, uint32* size, bool* eof); status_t ReadDir(uint64* cookie, DirEntry** dirents, uint32* count, bool* eof); status_t SetClientID(uint64* clientid, uint64* verifier); diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp index 3ce7f2c98b..641a4fc80e 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp @@ -205,6 +205,28 @@ RequestBuilder::PutRootFH() } +status_t +RequestBuilder::Read(const uint32* id, uint32 stateSeq, uint64 pos, uint32 len) +{ + if (fProcedure != ProcCompound) + return B_BAD_VALUE; + if (fRequest == NULL) + return B_NO_MEMORY; + + fRequest->Stream().AddUInt(OpRead); + 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().AddUInt(len); + + fOpCount++; + + return B_OK; +} + + status_t RequestBuilder::ReadDir(uint32 count, uint64* cookie, Attribute* attrs, uint32 attr_count) diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h index e3b5d301eb..e2c89b4ec5 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h @@ -33,6 +33,8 @@ public: uint32 stateSeq); status_t PutFH(const Filehandle& fh); status_t PutRootFH(); + status_t Read(const uint32* id, uint32 stateSeq, + uint64 pos, uint32 len); status_t ReadDir(uint32 count, uint64* cookie, Attribute* attrs, uint32 attr_count); status_t SetClientID(const RPC::Server* serv); 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 d9d3e355a1..ffdc7885da 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -156,6 +156,17 @@ nfs4_open(fs_volume* volume, fs_vnode* vnode, int openMode, void** _cookie) } +status_t +nfs4_read(fs_volume* volume, fs_vnode* vnode, void* _cookie, off_t pos, + void* buffer, size_t* length) +{ + Inode* inode = reinterpret_cast(vnode->private_node); + OpenFileCookie* cookie = reinterpret_cast(_cookie); + + return inode->Read(cookie, pos, buffer, length); +} + + static status_t nfs4_open_dir(fs_volume* volume, fs_vnode* vnode, void** _cookie) { @@ -299,7 +310,7 @@ fs_vnode_ops gNFSv4VnodeOps = { nfs4_open, NULL, // close() NULL, // free_cookie() - NULL, // read() + nfs4_read, NULL, // write, /* directory operations */ From 60a8140ded7da888e1ebf0d03ac6c20130b08aeb Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Tue, 5 Jun 2012 23:12:04 +0200 Subject: [PATCH 035/252] nfs4: Add close() and free_cookie() hooks --- .../kernel/file_systems/nfs4/Inode.cpp | 24 ++++++++++++++++++ src/add-ons/kernel/file_systems/nfs4/Inode.h | 1 + .../kernel/file_systems/nfs4/NFS4Defs.h | 1 + .../file_systems/nfs4/ReplyInterpreter.cpp | 16 ++++++++++++ .../file_systems/nfs4/ReplyInterpreter.h | 1 + .../file_systems/nfs4/RequestBuilder.cpp | 21 ++++++++++++++++ .../kernel/file_systems/nfs4/RequestBuilder.h | 2 ++ .../file_systems/nfs4/kernel_interface.cpp | 25 ++++++++++++++++--- 8 files changed, 88 insertions(+), 3 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index e4f855ddda..c3ee82e332 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -249,6 +249,30 @@ Inode::Open(int mode, OpenFileCookie* cookie) } +status_t +Inode::Close(OpenFileCookie* cookie) +{ + RequestBuilder req(ProcCompound); + req.PutFH(fHandle); + req.Close(cookie->fSeq, cookie->fStateId, cookie->fStateSeq); + + RPC::Reply *rpl; + fFilesystem->Server()->SendCall(req.Request(), &rpl); + ReplyInterpreter reply(rpl); + + status_t result; + result = reply.PutFH(); + if (result != B_OK) + return result; + + result = reply.Close(); + if (result != B_OK) + return result; + + return B_OK; +} + + status_t Inode::Read(OpenFileCookie* cookie, off_t pos, void* buffer, size_t* _length) { diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h b/src/add-ons/kernel/file_systems/nfs4/Inode.h index c75e197620..46959870ba 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -37,6 +37,7 @@ public: status_t Stat(struct stat* st); status_t Open(int mode, OpenFileCookie* cookie); + status_t Close(OpenFileCookie* cookie); status_t Read(OpenFileCookie* cookie, off_t pos, void* buffer, size_t* length); diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h index d9648a1cc5..8ded674387 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h @@ -22,6 +22,7 @@ enum Procedure { enum Opcode { OpAccess = 3, + OpClose = 4, OpGetAttr = 9, OpGetFH = 10, OpLookUp = 15, diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp index 1c158ee38c..4a8611b054 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp @@ -65,6 +65,22 @@ ReplyInterpreter::Access(uint32* supported, uint32* allowed) } +status_t +ReplyInterpreter::Close() +{ + status_t res = _OperationError(OpClose); + if (res != B_OK) + return res; + + fReply->Stream().GetUInt(); + fReply->Stream().GetUInt(); + fReply->Stream().GetUInt(); + fReply->Stream().GetUInt(); + + return fReply->Stream().IsEOF() ? B_BAD_VALUE : B_OK; +} + + // Bit Twiddling Hacks // http://graphics.stanford.edu/~seander/bithacks.html static inline uint32 sCountBits(uint32 v) diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h index c3d5395349..594e45b3fd 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h @@ -39,6 +39,7 @@ public: ~ReplyInterpreter(); status_t Access(uint32* supported, uint32* allowed); + status_t Close(); status_t GetAttr(AttrValue** attrs, uint32* count); status_t GetFH(Filehandle* fh); inline status_t LookUp(); diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp index 641a4fc80e..578605140e 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp @@ -53,6 +53,27 @@ RequestBuilder::Access() } +status_t +RequestBuilder::Close(uint32 seq, const uint32* id, uint32 stateSeq) +{ + if (fProcedure != ProcCompound) + return B_BAD_VALUE; + if (fRequest == NULL) + return B_NO_MEMORY; + + fRequest->Stream().AddUInt(OpClose); + fRequest->Stream().AddUInt(seq); + fRequest->Stream().AddUInt(stateSeq); + fRequest->Stream().AddUInt(id[0]); + fRequest->Stream().AddUInt(id[1]); + fRequest->Stream().AddUInt(id[2]); + + fOpCount++; + + return B_OK; +} + + status_t RequestBuilder::GetAttr(Attribute* attrs, uint32 count) { diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h index e2c89b4ec5..2e8be8c0cf 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h @@ -23,6 +23,8 @@ public: ~RequestBuilder(); status_t Access(); + status_t Close(uint32 seq, const uint32* id, + uint32 stateSeq); status_t GetAttr(Attribute* attrs, uint32 count); status_t GetFH(); status_t LookUp(const char* name); 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 ffdc7885da..ac7421d1b6 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -156,7 +156,26 @@ nfs4_open(fs_volume* volume, fs_vnode* vnode, int openMode, void** _cookie) } -status_t +static status_t +nfs4_close(fs_volume* volume, fs_vnode* vnode, void* cookie) +{ + return B_OK; +} + + +static status_t +nfs4_free_cookie(fs_volume* volume, fs_vnode* vnode, void* _cookie) +{ + Inode* inode = reinterpret_cast(vnode->private_node); + OpenFileCookie* cookie = reinterpret_cast(_cookie); + inode->Close(cookie); + delete cookie; + + return B_OK; +} + + +static status_t nfs4_read(fs_volume* volume, fs_vnode* vnode, void* _cookie, off_t pos, void* buffer, size_t* length) { @@ -308,8 +327,8 @@ fs_vnode_ops gNFSv4VnodeOps = { /* file operations */ NULL, // create() nfs4_open, - NULL, // close() - NULL, // free_cookie() + nfs4_close, + nfs4_free_cookie, nfs4_read, NULL, // write, From a01e1e9961b5a7c5f17fa006c68371e2f5f9f09b Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Tue, 5 Jun 2012 23:22:19 +0200 Subject: [PATCH 036/252] nfs4: k- variants of socket functions are not really needed --- .../kernel/file_systems/nfs4/Connection.cpp | 44 ++++++------------- .../kernel/file_systems/nfs4/Connection.h | 3 -- .../file_systems/nfs4/kernel_interface.cpp | 7 --- 3 files changed, 13 insertions(+), 41 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Connection.cpp b/src/add-ons/kernel/file_systems/nfs4/Connection.cpp index 0143f79bc6..5b455b5545 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Connection.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Connection.cpp @@ -14,7 +14,6 @@ #include #include -#include #include @@ -22,9 +21,6 @@ #define MAX_PACKET_SIZE 65535 -KSOCKET_MODULE_DECL; - - bool ServerAddress::operator==(const ServerAddress& x) { @@ -66,7 +62,7 @@ Connection::Connection(const sockaddr_in& addr, Transport proto, bool markers) Connection::~Connection() { if (fSock != -1) - kclosesocket(fSock); + close(fSock); mutex_destroy(&fSockLock); } @@ -76,7 +72,7 @@ Connection::GetLocalID(ServerAddress* addr) { struct sockaddr_in saddr; socklen_t slen = sizeof(addr); - status_t result = kgetsockname(fSock, (struct sockaddr*)&saddr, &slen); + status_t result = getsockname(fSock, (struct sockaddr*)&saddr, &slen); if (result != B_OK) return result; @@ -105,7 +101,7 @@ Connection::_SendStream(const void* buffer, uint32 size) uint32 sent = 0; mutex_lock(&fSockLock); do { - result = ksend(fSock, buf + sent, size + sizeof(uint32) - sent, 0); + result = send(fSock, buf + sent, size + sizeof(uint32) - sent, 0); sent += result; } while (result > 0 && sent < size + sizeof(uint32)); mutex_unlock(&fSockLock); @@ -127,7 +123,7 @@ status_t Connection::_SendPacket(const void* buffer, uint32 size) { // send on DGRAM sockets is atomic. No need to lock. - status_t result = ksend(fSock, buffer, size, 0); + status_t result = send(fSock, buffer, size, 0); if (result < 0) return errno; @@ -149,7 +145,7 @@ Connection::_ReceiveStream(void** pbuffer, uint32* psize) // There is only one listener thread per connection. No need to lock. uint32 received = 0; do { - result = krecv(fSock, &record_size + received, + result = recv(fSock, &record_size + received, sizeof(record_size) - received, 0); received += result; } while (result > 0 && received < sizeof(record_size)); @@ -175,7 +171,7 @@ Connection::_ReceiveStream(void** pbuffer, uint32* psize) received = 0; do { - result = krecv(fSock, (uint8*)buffer + size + received, + result = recv(fSock, (uint8*)buffer + size + received, record_size - received, 0); received += result; } while (result > 0 && received < sizeof(record_size)); @@ -207,7 +203,7 @@ Connection::_ReceivePacket(void** pbuffer, uint32* psize) return B_NO_MEMORY; // There is only one listener thread per connection. No need to lock. - size = krecv(fSock, buffer, size, 0); + size = recv(fSock, buffer, size, 0); if (size < 0) { result = errno; free(buffer); @@ -257,10 +253,10 @@ Connection::_Connect() { switch (fProtocol) { case ProtocolTCP: - fSock = ksocket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + fSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); break; case ProtocolUDP: - fSock = ksocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + fSock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); break; default: return B_BAD_VALUE; @@ -268,11 +264,11 @@ Connection::_Connect() if (fSock < 0) return errno; - status_t result = kconnect(fSock, (struct sockaddr*)&fServerAddress, + status_t result = connect(fSock, (struct sockaddr*)&fServerAddress, fServerAddress.sin_len); if (result < 0) { result = errno; - kclosesocket(fSock); + close(fSock); return result; } @@ -283,7 +279,7 @@ Connection::_Connect() status_t Connection::Reconnect() { - kclosesocket(fSock); + close(fSock); return _Connect(); } @@ -293,20 +289,6 @@ Connection::Disconnect() { int sock = fSock; fSock = -1; - kclosesocket(sock); -} - - -status_t -Connection::Init() -{ - return ksocket_init(); -} - - -status_t -Connection::CleanUp() -{ - return ksocket_cleanup(); + close(sock); } diff --git a/src/add-ons/kernel/file_systems/nfs4/Connection.h b/src/add-ons/kernel/file_systems/nfs4/Connection.h index 041c5deda2..6336f9e0f0 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Connection.h +++ b/src/add-ons/kernel/file_systems/nfs4/Connection.h @@ -45,9 +45,6 @@ public: status_t Reconnect(); void Disconnect(); - static status_t Init(); - static status_t CleanUp(); - private: Connection(const sockaddr_in& addr, Transport proto, bool markers); 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 ac7421d1b6..bcb3bbb382 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -243,10 +243,6 @@ nfs4_init() { dprintf("NFS4 Init\n"); - status_t result = Connection::Init(); - if (result != B_OK) - return result; - gRPCServerManager = new(std::nothrow) RPC::ServerManager; if (gRPCServerManager == NULL) return B_NO_MEMORY; @@ -261,9 +257,6 @@ nfs4_uninit() delete gRPCServerManager; - status_t result = Connection::CleanUp(); - if (result != B_OK) - return result; return B_OK; } From 631d9e9867f037d35944f4fce87fdfef5f63e4da Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Wed, 6 Jun 2012 00:58:23 +0200 Subject: [PATCH 037/252] nfs4: Add access() hook --- .../kernel/file_systems/nfs4/Inode.cpp | 41 +++++++++++++++++++ src/add-ons/kernel/file_systems/nfs4/Inode.h | 1 + .../file_systems/nfs4/kernel_interface.cpp | 10 ++++- 3 files changed, 51 insertions(+), 1 deletion(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index c3ee82e332..4b0981f067 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -132,6 +132,47 @@ Inode::LookUp(const char* name, ino_t* id) } +status_t +Inode::Access(int mode) +{ + RequestBuilder req(ProcCompound); + req.PutFH(fHandle); + req.Access(); + + RPC::Reply *rpl; + fFilesystem->Server()->SendCall(req.Request(), &rpl); + ReplyInterpreter reply(rpl); + + status_t result; + result = reply.PutFH(); + if (result != B_OK) + return result; + + uint32 allowed; + result = reply.Access(NULL, &allowed); + if (result != B_OK) + return result; + + int acc = 0; + if ((allowed & ACCESS4_READ) != 0) + acc |= R_OK; + + if (fType == NF4DIR && (allowed & ACCESS4_LOOKUP) != 0) + acc |= X_OK | R_OK; + + if (fType != NF4DIR && (allowed & ACCESS4_EXECUTE) != 0) + acc |= X_OK; + + if ((allowed & ACCESS4_MODIFY) != 0) + acc |= W_OK; + + if ((mode & acc) != mode) + return B_NOT_ALLOWED; + + return B_OK; +} + + status_t Inode::Stat(struct stat* st) { diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h b/src/add-ons/kernel/file_systems/nfs4/Inode.h index 46959870ba..6813ed46ac 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -34,6 +34,7 @@ public: inline const char* Name() const; status_t LookUp(const char* name, ino_t* id); + status_t Access(int mode); status_t Stat(struct stat* st); status_t Open(int mode, OpenFileCookie* cookie); 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 bcb3bbb382..d0180fb404 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -131,6 +131,14 @@ nfs4_put_vnode(fs_volume* volume, fs_vnode* vnode, bool reenter) } +static status_t +nfs4_access(fs_volume* volume, fs_vnode* vnode, int mode) +{ + Inode* inode = reinterpret_cast(vnode->private_node); + return inode->Access(mode); +} + + static status_t nfs4_read_stat(fs_volume* volume, fs_vnode* vnode, struct stat* stat) { @@ -312,7 +320,7 @@ fs_vnode_ops gNFSv4VnodeOps = { NULL, // unlink() NULL, // rename() - NULL, // access() + nfs4_access, nfs4_read_stat, NULL, // write_stat() NULL, // fs_preallocate() From b0368e77c9f23cd6e4c5d5bc4f79618204c5f3d3 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Wed, 6 Jun 2012 01:25:22 +0200 Subject: [PATCH 038/252] nfs4: Allow open() on directories --- .../file_systems/nfs4/kernel_interface.cpp | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) 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 d0180fb404..d34d25e0df 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -150,12 +150,19 @@ nfs4_read_stat(fs_volume* volume, fs_vnode* vnode, struct stat* stat) static status_t nfs4_open(fs_volume* volume, fs_vnode* vnode, int openMode, void** _cookie) { + Inode* inode = reinterpret_cast(vnode->private_node); + + if (inode->Type() == S_IFDIR) { + *_cookie = NULL; + return B_OK; + } + OpenFileCookie* cookie = new OpenFileCookie; if (cookie == NULL) return B_NO_MEMORY; *_cookie = cookie; - Inode* inode = reinterpret_cast(vnode->private_node); + status_t result = inode->Open(openMode, cookie); if (result != B_OK) delete cookie; @@ -175,6 +182,10 @@ static status_t nfs4_free_cookie(fs_volume* volume, fs_vnode* vnode, void* _cookie) { Inode* inode = reinterpret_cast(vnode->private_node); + + if (inode->Type() == S_IFDIR) + return B_OK; + OpenFileCookie* cookie = reinterpret_cast(_cookie); inode->Close(cookie); delete cookie; @@ -188,6 +199,10 @@ nfs4_read(fs_volume* volume, fs_vnode* vnode, void* _cookie, off_t pos, void* buffer, size_t* length) { Inode* inode = reinterpret_cast(vnode->private_node); + + if (inode->Type() == S_IFDIR) + return B_IS_A_DIRECTORY; + OpenFileCookie* cookie = reinterpret_cast(_cookie); return inode->Read(cookie, pos, buffer, length); From 5310ed9ee18ae2c2011afa76e1a6aaec6162ed00 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Wed, 6 Jun 2012 02:00:51 +0200 Subject: [PATCH 039/252] nfs4: Fix off-by-one bug in READDIR decoding --- src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp index 4a8611b054..fc020c0f81 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp @@ -212,7 +212,7 @@ ReplyInterpreter::ReadDir(uint64* cookie, DirEntry** dirents, uint32* _count, return B_NO_MEMORY; isNext = fReply->Stream().GetBoolean(); - while (isNext && count <= *_count) { + while (isNext && count < *_count) { cookie[0] = fReply->Stream().GetUHyper(); entries[count].fName = fReply->Stream().GetString(); From 01d6381d20122ada695eefd7696b156800808662 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Mon, 11 Jun 2012 20:03:57 +0200 Subject: [PATCH 040/252] nfs4: Add Request class for better handling of NFS4 requests --- .../kernel/file_systems/nfs4/Filesystem.cpp | 15 +- .../kernel/file_systems/nfs4/Inode.cpp | 166 +++++++++++------- src/add-ons/kernel/file_systems/nfs4/Jamfile | 1 + .../file_systems/nfs4/ReplyInterpreter.cpp | 17 +- .../file_systems/nfs4/ReplyInterpreter.h | 30 +++- .../kernel/file_systems/nfs4/Request.cpp | 31 ++++ .../kernel/file_systems/nfs4/Request.h | 58 ++++++ .../file_systems/nfs4/RequestBuilder.cpp | 28 ++- .../kernel/file_systems/nfs4/RequestBuilder.h | 18 +- src/add-ons/kernel/file_systems/nfs4/XDR.cpp | 11 ++ src/add-ons/kernel/file_systems/nfs4/XDR.h | 1 + 11 files changed, 291 insertions(+), 85 deletions(-) create mode 100644 src/add-ons/kernel/file_systems/nfs4/Request.cpp create mode 100644 src/add-ons/kernel/file_systems/nfs4/Request.h diff --git a/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp b/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp index aa9748c42c..6502c0f2f5 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp @@ -11,8 +11,7 @@ #include -#include "ReplyInterpreter.h" -#include "RequestBuilder.h" +#include "Request.h" #include "Inode.h" @@ -33,7 +32,9 @@ status_t Filesystem::Mount(Filesystem** pfs, RPC::Server* serv, const char* fsPath, dev_t id) { - RequestBuilder req(ProcCompound); + Request request(serv); + RequestBuilder& req = request.Builder(); + req.PutRootFH(); // Better way of doing this will be needed @@ -62,11 +63,11 @@ Filesystem::Mount(Filesystem** pfs, RPC::Server* serv, const char* fsPath, Attribute attr[] = { FATTR4_FH_EXPIRE_TYPE }; req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); - RPC::Reply *rpl; - serv->SendCall(req.Request(), &rpl); - ReplyInterpreter reply(rpl); + status_t result = request.Send(); + if (result != B_OK) + return result; - status_t result; + ReplyInterpreter& reply = request.Reply(); result = reply.PutRootFH(); if (result != B_OK) diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index 4b0981f067..a7e92285f7 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -12,8 +12,7 @@ #include #include -#include "ReplyInterpreter.h" -#include "RequestBuilder.h" +#include "Request.h" // Creating Inode object from Filehandle probably is not a good idea when @@ -25,17 +24,20 @@ Inode::Inode(Filesystem* fs, const FileInfo &fi) fParentFH(fi.fParent), fName(strdup(fi.fName)) { - RequestBuilder req(ProcCompound); + Request request(fFilesystem->Server()); + RequestBuilder& req = request.Builder(); + req.PutFH(fHandle); Attribute attr[] = { FATTR4_TYPE, FATTR4_FILEID }; req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); - RPC::Reply *rpl; - fs->Server()->SendCall(req.Request(), &rpl); - ReplyInterpreter reply(rpl); + status_t result = request.Send(); + if (result != B_OK) + return; + + ReplyInterpreter& reply = request.Reply(); - status_t result; result = reply.PutFH(); if (result != B_OK) return; @@ -79,7 +81,9 @@ Inode::LookUp(const char* name, ino_t* id) return B_OK; } - RequestBuilder req(ProcCompound); + Request request(fFilesystem->Server()); + RequestBuilder& req = request.Builder(); + req.PutFH(fHandle); if (!strcmp(name, "..")) @@ -92,11 +96,13 @@ Inode::LookUp(const char* name, ino_t* id) Attribute attr[] = { FATTR4_FILEID }; req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); - RPC::Reply *rpl; - fFilesystem->Server()->SendCall(req.Request(), &rpl); - ReplyInterpreter reply(rpl); + status_t result = request.Send(); + if (result != B_OK) + return result; - status_t result = reply.PutFH(); + ReplyInterpreter& reply = request.Reply(); + + result = reply.PutFH(); if (result != B_OK) return result; @@ -135,15 +141,18 @@ Inode::LookUp(const char* name, ino_t* id) status_t Inode::Access(int mode) { - RequestBuilder req(ProcCompound); + Request request(fFilesystem->Server()); + RequestBuilder& req = request.Builder(); + req.PutFH(fHandle); req.Access(); - RPC::Reply *rpl; - fFilesystem->Server()->SendCall(req.Request(), &rpl); - ReplyInterpreter reply(rpl); + status_t result = request.Send(); + if (result != B_OK) + return result; + + ReplyInterpreter& reply = request.Reply(); - status_t result; result = reply.PutFH(); if (result != B_OK) return result; @@ -176,17 +185,20 @@ Inode::Access(int mode) status_t Inode::Stat(struct stat* st) { - RequestBuilder req(ProcCompound); + Request request(fFilesystem->Server()); + RequestBuilder& req = request.Builder(); + req.PutFH(fHandle); Attribute attr[] = { FATTR4_SIZE, FATTR4_MODE, FATTR4_NUMLINKS }; req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); - RPC::Reply *rpl; - fFilesystem->Server()->SendCall(req.Request(), &rpl); - ReplyInterpreter reply(rpl); + status_t result = request.Send(); + if (result != B_OK) + return result; + + ReplyInterpreter& reply = request.Reply(); - status_t result; result = reply.PutFH(); if (result != B_OK) return result; @@ -231,34 +243,41 @@ Inode::Open(int mode, OpenFileCookie* cookie) { cookie->fSeq = 0; - RequestBuilder req_setid(ProcCompound); - req_setid.SetClientID(fFilesystem->Server()); + Request request(fFilesystem->Server()); + request.Builder().SetClientID(fFilesystem->Server()); - RPC::Reply *rpl; - fFilesystem->Server()->SendCall(req_setid.Request(), &rpl); - ReplyInterpreter setid(rpl); + status_t result = request.Send(); + if (result != B_OK) + return result; uint64 id, ver; - status_t result = setid.SetClientID(&id, &ver); + result = request.Reply().SetClientID(&id, &ver); if (result != B_OK) return result; - RequestBuilder req_conf(ProcCompound); - req_conf.SetClientIDConfirm(id, ver); + request.Reset(); + request.Builder().SetClientIDConfirm(id, ver); - fFilesystem->Server()->SendCall(req_conf.Request(), &rpl); - ReplyInterpreter conf(rpl); - - result = conf.SetClientIDConfirm(); + result = request.Send(); if (result != B_OK) return result; - RequestBuilder req(ProcCompound); + result = request.Reply().SetClientIDConfirm(); + if (result != B_OK) + return result; + + request.Reset(); + RequestBuilder& req = request.Builder(); + req.PutFH(fParentFH); req.Open(cookie->fSeq, OPEN4_SHARE_ACCESS_READ, id, OPEN4_NOCREATE, fName); cookie->fSeq++; - fFilesystem->Server()->SendCall(req.Request(), &rpl); - ReplyInterpreter reply(rpl); + + result = request.Send(); + if (result != B_OK) + return result; + + ReplyInterpreter& reply = request.Reply(); result = reply.PutFH(); if (result != B_OK) @@ -270,12 +289,14 @@ Inode::Open(int mode, OpenFileCookie* cookie) return result; if (confirm) { - RequestBuilder req(ProcCompound); + request.Reset(); req.PutFH(fHandle); req.OpenConfirm(cookie->fSeq, cookie->fStateId, cookie->fStateSeq); cookie->fSeq++; - fFilesystem->Server()->SendCall(req.Request(), &rpl); - ReplyInterpreter reply(rpl); + + result = request.Send(); + if (result != B_OK) + return result; result = reply.PutFH(); if (result != B_OK) @@ -293,15 +314,18 @@ Inode::Open(int mode, OpenFileCookie* cookie) status_t Inode::Close(OpenFileCookie* cookie) { - RequestBuilder req(ProcCompound); + Request request(fFilesystem->Server()); + RequestBuilder& req = request.Builder(); + req.PutFH(fHandle); req.Close(cookie->fSeq, cookie->fStateId, cookie->fStateSeq); - RPC::Reply *rpl; - fFilesystem->Server()->SendCall(req.Request(), &rpl); - ReplyInterpreter reply(rpl); + status_t result = request.Send(); + if (result != B_OK) + return result; + + ReplyInterpreter& reply = request.Reply(); - status_t result; result = reply.PutFH(); if (result != B_OK) return result; @@ -322,16 +346,19 @@ Inode::Read(OpenFileCookie* cookie, off_t pos, void* buffer, size_t* _length) uint32 len = 0; while (size < *_length && !eof) { - RequestBuilder req(ProcCompound); + Request request(fFilesystem->Server()); + RequestBuilder& req = request.Builder(); + req.PutFH(fHandle); req.Read(cookie->fStateId, cookie->fStateSeq, pos + size, *_length - size); - RPC::Reply *rpl; - fFilesystem->Server()->SendCall(req.Request(), &rpl); - ReplyInterpreter reply(rpl); + status_t result = request.Send(); + if (result != B_OK) + return result; + + ReplyInterpreter& reply = request.Reply(); - status_t result; result = reply.PutFH(); if (result != B_OK) return result; @@ -355,15 +382,18 @@ Inode::OpenDir(uint64* cookie) if (fType != NF4DIR) return B_NOT_A_DIRECTORY; - RequestBuilder req(ProcCompound); + Request request(fFilesystem->Server()); + RequestBuilder& req = request.Builder(); + req.PutFH(fHandle); req.Access(); - RPC::Reply *rpl; - fFilesystem->Server()->SendCall(req.Request(), &rpl); - ReplyInterpreter reply(rpl); + status_t result = request.Send(); + if (result != B_OK) + return result; + + ReplyInterpreter& reply = request.Reply(); - status_t result; result = reply.PutFH(); if (result != B_OK) return result; @@ -387,17 +417,20 @@ status_t Inode::_ReadDirOnce(DirEntry** dirents, uint32* count, uint64* cookie, bool* eof) { - RequestBuilder req(ProcCompound); + Request request(fFilesystem->Server()); + RequestBuilder& req = request.Builder(); + req.PutFH(fHandle); Attribute attr[] = { FATTR4_FILEID }; req.ReadDir(*count, cookie, attr, sizeof(attr) / sizeof(Attribute)); - RPC::Reply *rpl; - fFilesystem->Server()->SendCall(req.Request(), &rpl); - ReplyInterpreter reply(rpl); + status_t result = request.Send(); + if (result != B_OK) + return result; + + ReplyInterpreter& reply = request.Reply(); - status_t result; result = reply.PutFH(); if (result != B_OK) return result; @@ -431,18 +464,21 @@ Inode::_FillDirEntry(struct dirent* de, ino_t id, const char* name, uint32 pos, status_t Inode::_ReadDirUp(struct dirent* de, uint32 pos, uint32 size) { - RequestBuilder req(ProcCompound); + Request request(fFilesystem->Server()); + RequestBuilder& req = request.Builder(); + req.PutFH(fHandle); req.LookUpUp(); req.GetFH(); Attribute attr[] = { FATTR4_FILEID }; req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); - RPC::Reply *rpl; - fFilesystem->Server()->SendCall(req.Request(), &rpl); - ReplyInterpreter reply(rpl); + status_t result = request.Send(); + if (result != B_OK) + return result; + + ReplyInterpreter& reply = request.Reply(); - status_t result; result = reply.PutFH(); if (result != B_OK) return result; diff --git a/src/add-ons/kernel/file_systems/nfs4/Jamfile b/src/add-ons/kernel/file_systems/nfs4/Jamfile index 81f3f46b8a..e1b56c1186 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Jamfile +++ b/src/add-ons/kernel/file_systems/nfs4/Jamfile @@ -8,6 +8,7 @@ KernelAddon nfs4 : Inode.cpp kernel_interface.cpp ReplyInterpreter.cpp + Request.cpp RequestBuilder.cpp RPCAuth.cpp RPCCall.cpp diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp index fc020c0f81..5782247493 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp @@ -34,9 +34,8 @@ ReplyInterpreter::ReplyInterpreter(RPC::Reply* reply) : fReply(reply) { - fReply->Stream().GetUInt(); - fReply->Stream().GetOpaque(NULL); - fReply->Stream().GetUInt(); + if (reply != NULL) + _ParseHeader(); } @@ -46,6 +45,15 @@ ReplyInterpreter::~ReplyInterpreter() } +void +ReplyInterpreter::_ParseHeader() +{ + fReply->Stream().GetUInt(); + fReply->Stream().GetOpaque(NULL); + fReply->Stream().GetUInt(); +} + + status_t ReplyInterpreter::Access(uint32* supported, uint32* allowed) { @@ -330,6 +338,9 @@ ReplyInterpreter::_DecodeAttrs(XDR::ReadStream& str, AttrValue** attrs, status_t ReplyInterpreter::_OperationError(Opcode op) { + if (fReply == NULL) + return B_NOT_INITIALIZED; + if (fReply->Error() != B_OK || fReply->Stream().IsEOF()) return fReply->Error(); diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h index 594e45b3fd..e0c56f6297 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h @@ -35,9 +35,12 @@ struct DirEntry { class ReplyInterpreter { public: - ReplyInterpreter(RPC::Reply* reply); + ReplyInterpreter(RPC::Reply* reply = NULL); ~ReplyInterpreter(); + inline status_t SetTo(RPC::Reply* reply); + inline void Reset(); + status_t Access(uint32* supported, uint32* allowed); status_t Close(); status_t GetAttr(AttrValue** attrs, uint32* count); @@ -55,6 +58,8 @@ public: inline status_t SetClientIDConfirm(); private: + void _ParseHeader(); + status_t _DecodeAttrs(XDR::ReadStream& stream, AttrValue** attrs, uint32* count); status_t _OperationError(Opcode op); @@ -65,6 +70,29 @@ private: }; +inline status_t +ReplyInterpreter::SetTo(RPC::Reply* _reply) +{ + if (fReply != NULL) + return B_DONT_DO_THAT; + + fReply = _reply; + + if (fReply != NULL) + _ParseHeader(); + + return B_OK; +} + + +inline void +ReplyInterpreter::Reset() +{ + delete fReply; + fReply = NULL; +} + + inline status_t ReplyInterpreter::LookUp() { diff --git a/src/add-ons/kernel/file_systems/nfs4/Request.cpp b/src/add-ons/kernel/file_systems/nfs4/Request.cpp new file mode 100644 index 0000000000..83760ba01f --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/Request.cpp @@ -0,0 +1,31 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ + + +#include "Request.h" + + +status_t +Request::Send() +{ + RPC::Reply *rpl; + status_t result = fServer->SendCall(fBuilder.Request(), &rpl); + if (result != B_OK) + return result; + + return fReply.SetTo(rpl); +} + + +void +Request::Reset() +{ + fBuilder.Reset(); + fReply.Reset(); +} + diff --git a/src/add-ons/kernel/file_systems/nfs4/Request.h b/src/add-ons/kernel/file_systems/nfs4/Request.h new file mode 100644 index 0000000000..3db4e42e10 --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/Request.h @@ -0,0 +1,58 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ +#ifndef REQUEST_H +#define REQUEST_H + + +#include "ReplyInterpreter.h" +#include "RequestBuilder.h" +#include "RPCServer.h" + + +class Request { +public: + inline Request(RPC::Server* serv); + + inline RequestBuilder& Builder(); + inline ReplyInterpreter& Reply(); + + status_t Send(); + void Reset(); + +private: + RPC::Server* fServer; + + RequestBuilder fBuilder; + ReplyInterpreter fReply; +}; + + +inline +Request::Request(RPC::Server* serv) + : + fServer(serv) +{ +} + + +inline RequestBuilder& +Request::Builder() +{ + return fBuilder; +} + + +inline ReplyInterpreter& +Request::Reply() +{ + return fReply; +} + + +#endif // REQUEST_H + diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp index 578605140e..414322fd3a 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp @@ -16,9 +16,27 @@ RequestBuilder::RequestBuilder(Procedure proc) : fOpCount(0), fProcedure(proc), - fRequest(RPC::Call::Create(proc, RPC::Auth::CreateSys(), - RPC::Auth::CreateNone())) + fRequest(NULL) { + _InitHeader(); +} + + +RequestBuilder::~RequestBuilder() +{ + delete fRequest; +} + + +void +RequestBuilder::_InitHeader() +{ + fRequest = RPC::Call::Create(fProcedure, RPC::Auth::CreateSys(), + RPC::Auth::CreateNone()); + + if (fRequest == NULL) + return; + if (fProcedure == ProcCompound) { fRequest->Stream().AddOpaque(NULL, 0); fRequest->Stream().AddUInt(0); @@ -29,12 +47,6 @@ RequestBuilder::RequestBuilder(Procedure proc) } -RequestBuilder::~RequestBuilder() -{ - delete fRequest; -} - - status_t RequestBuilder::Access() { diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h index 2e8be8c0cf..86f5070e71 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h @@ -19,9 +19,11 @@ class RequestBuilder { public: - RequestBuilder(Procedure proc); + RequestBuilder(Procedure p = ProcCompound); ~RequestBuilder(); + inline void Reset(Procedure proc = ProcCompound); + status_t Access(); status_t Close(uint32 seq, const uint32* id, uint32 stateSeq); @@ -45,6 +47,8 @@ public: RPC::Call* Request(); private: + void _InitHeader(); + void _AttrBitmap(XDR::WriteStream& stream, Attribute* attrs, uint32 count); @@ -57,5 +61,17 @@ private: }; +inline void +RequestBuilder::Reset(Procedure proc) +{ + fRequest->Stream().Clear(); + fOpCount = 0; + fProcedure = proc; + delete fRequest; + + _InitHeader(); +} + + #endif // REQUESTBUILDER_H diff --git a/src/add-ons/kernel/file_systems/nfs4/XDR.cpp b/src/add-ons/kernel/file_systems/nfs4/XDR.cpp index 6d6dd0d90e..73455c99b0 100644 --- a/src/add-ons/kernel/file_systems/nfs4/XDR.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/XDR.cpp @@ -190,6 +190,17 @@ WriteStream::~WriteStream() } +void +WriteStream::Clear() +{ + free(fBuffer); + fSize = kInitialSize; + fBuffer = reinterpret_cast(malloc(fSize)); + fError = B_OK; + fPosition = 0; +} + + status_t WriteStream::InsertUInt(Stream::Position pos, uint32 x) { diff --git a/src/add-ons/kernel/file_systems/nfs4/XDR.h b/src/add-ons/kernel/file_systems/nfs4/XDR.h index 00cfce3a9e..6f9aee292b 100644 --- a/src/add-ons/kernel/file_systems/nfs4/XDR.h +++ b/src/add-ons/kernel/file_systems/nfs4/XDR.h @@ -65,6 +65,7 @@ public: virtual ~WriteStream(); inline int Size() const; + void Clear(); status_t InsertUInt(Stream::Position pos, uint32 x); From 3ce57b347fe923dde6bcdba518a1ec479d43e84b Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Mon, 11 Jun 2012 20:24:32 +0200 Subject: [PATCH 041/252] nfs4: Make RPC calls asynchronous --- .../kernel/file_systems/nfs4/RPCServer.cpp | 40 ++++++++++++------- .../kernel/file_systems/nfs4/RPCServer.h | 22 ++++++++++ .../kernel/file_systems/nfs4/Request.cpp | 18 ++++++++- .../kernel/file_systems/nfs4/Request.h | 2 + 4 files changed, 67 insertions(+), 15 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp b/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp index fed27887e6..5d62e265e2 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp @@ -119,8 +119,26 @@ Server::_StartListening() status_t Server::SendCall(Call* call, Reply** reply) { - status_t result; + Request* req; + status_t result = SendCallAsync(call, reply, &req); + if (result != B_OK) + return result; + result = WaitCall(req); + if (result != B_OK) { + CancelCall(req); + delete req; + return result; + } + + delete req; + return B_OK; +} + + +status_t +Server::SendCallAsync(Call* call, Reply** reply, Request** request) +{ if (fThreadError != B_OK) return fThreadError; @@ -137,21 +155,15 @@ Server::SendCall(Call* call, Reply** reply) fRequests.AddRequest(req); XDR::WriteStream& stream = call->Stream(); - result = fConnection->Send(stream.Buffer(), stream.Size()); - if (result != B_OK) - goto out_cancel; + status_t result = fConnection->Send(stream.Buffer(), stream.Size()); + if (result != B_OK) { + fRequests.FindRequest(xid); + delete req; + return result; + } - result = req->fEvent.Wait(B_RELATIVE_TIMEOUT, kWaitTime); - if (result != B_OK) - goto out_cancel; - - delete req; + *request = req; return B_OK; - -out_cancel: - fRequests.FindRequest(xid); - delete req; - return result; } diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCServer.h b/src/add-ons/kernel/file_systems/nfs4/RPCServer.h index 13cf8b2256..bd10454ccc 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RPCServer.h +++ b/src/add-ons/kernel/file_systems/nfs4/RPCServer.h @@ -50,6 +50,12 @@ public: status_t SendCall(Call* call, Reply** reply); + status_t SendCallAsync(Call* call, Reply** reply, + Request** request); + inline status_t WaitCall(Request* request, + bigtime_t time = kWaitTime); + inline status_t CancelCall(Request* request); + status_t Repair(); inline const ServerAddress& ID() const; @@ -75,6 +81,22 @@ private: static const bigtime_t kWaitTime = 1000000; }; + +inline status_t +Server::WaitCall(Request* request, bigtime_t time) +{ + return request->fEvent.Wait(B_RELATIVE_TIMEOUT, time); +} + + +inline status_t +Server::CancelCall(Request* request) +{ + fRequests.FindRequest(request->fXID); + return B_OK; +} + + inline const ServerAddress& Server::ID() const { diff --git a/src/add-ons/kernel/file_systems/nfs4/Request.cpp b/src/add-ons/kernel/file_systems/nfs4/Request.cpp index 83760ba01f..65efca366d 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Request.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Request.cpp @@ -12,12 +12,28 @@ status_t Request::Send() +{ + return _TrySend(); +} + + +status_t +Request::_TrySend() { RPC::Reply *rpl; - status_t result = fServer->SendCall(fBuilder.Request(), &rpl); + RPC::Request *rpc; + + status_t result = fServer->SendCallAsync(fBuilder.Request(), &rpl, &rpc); if (result != B_OK) return result; + result = fServer->WaitCall(rpc); + if (result != B_OK) { + fServer->CancelCall(rpc); + delete rpc; + return result; + } + return fReply.SetTo(rpl); } diff --git a/src/add-ons/kernel/file_systems/nfs4/Request.h b/src/add-ons/kernel/file_systems/nfs4/Request.h index 3db4e42e10..60dc99b8f5 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Request.h +++ b/src/add-ons/kernel/file_systems/nfs4/Request.h @@ -25,6 +25,8 @@ public: void Reset(); private: + status_t _TrySend(); + RPC::Server* fServer; RequestBuilder fBuilder; From 5945c55ae441fb36adca961ed97ab56d978443be Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Mon, 11 Jun 2012 21:41:00 +0200 Subject: [PATCH 042/252] nfs4: Correctly handle timeouts and other rpc errors --- .../kernel/file_systems/nfs4/RPCServer.cpp | 24 +++++++-- .../kernel/file_systems/nfs4/RPCServer.h | 1 + .../kernel/file_systems/nfs4/Request.cpp | 51 +++++++++++++++++-- .../kernel/file_systems/nfs4/Request.h | 5 +- 4 files changed, 70 insertions(+), 11 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp b/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp index 5d62e265e2..329daec6ec 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp @@ -154,15 +154,28 @@ Server::SendCallAsync(Call* call, Reply** reply, Request** request) fRequests.AddRequest(req); + *request = req; + return ResendCallAsync(call, req); +} + + +status_t +Server::ResendCallAsync(Call* call, Request* req) +{ + if (fThreadError != B_OK) { + fRequests.FindRequest(req->fXID); + delete req; + return fThreadError; + } + XDR::WriteStream& stream = call->Stream(); status_t result = fConnection->Send(stream.Buffer(), stream.Size()); if (result != B_OK) { - fRequests.FindRequest(xid); + fRequests.FindRequest(req->fXID); delete req; return result; } - *request = req; return B_OK; } @@ -198,7 +211,9 @@ Server::_Listener() while (!fThreadCancel) { result = fConnection->Receive(&buffer, &size); - if (result != B_OK) { + if (result == B_NO_MEMORY) + continue; + else if (result != B_OK) { fThreadError = result; return result; } @@ -206,8 +221,7 @@ Server::_Listener() Reply* reply = new(std::nothrow) Reply(buffer, size); if (reply == NULL) { free(buffer); - fThreadError = result; - return B_NO_MEMORY; + continue; } Request* req = fRequests.FindRequest(reply->GetXID()); diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCServer.h b/src/add-ons/kernel/file_systems/nfs4/RPCServer.h index bd10454ccc..8241cd6ee3 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RPCServer.h +++ b/src/add-ons/kernel/file_systems/nfs4/RPCServer.h @@ -52,6 +52,7 @@ public: status_t SendCallAsync(Call* call, Reply** reply, Request** request); + status_t ResendCallAsync(Call* call, Request* req); inline status_t WaitCall(Request* request, bigtime_t time = kWaitTime); inline status_t CancelCall(Request* request); diff --git a/src/add-ons/kernel/file_systems/nfs4/Request.cpp b/src/add-ons/kernel/file_systems/nfs4/Request.cpp index 65efca366d..125bdc9aa8 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Request.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Request.cpp @@ -13,12 +13,17 @@ status_t Request::Send() { - return _TrySend(); + switch (fServer->ID().fProtocol) { + case ProtocolUDP: return _SendUDP(); + case ProtocolTCP: return _SendTCP(); + } + + return B_BAD_VALUE; } status_t -Request::_TrySend() +Request::_SendUDP() { RPC::Reply *rpl; RPC::Request *rpc; @@ -29,15 +34,51 @@ Request::_TrySend() result = fServer->WaitCall(rpc); if (result != B_OK) { - fServer->CancelCall(rpc); - delete rpc; - return result; + int attempts = 1; + while (result != B_OK && attempts++ < kRetryLimit) + result = fServer->ResendCallAsync(fBuilder.Request(), rpc); + + if (attempts == kRetryLimit) { + fServer->CancelCall(rpc); + delete rpc; + return result; + } } return fReply.SetTo(rpl); } +status_t +Request::_SendTCP() +{ + RPC::Reply *rpl; + RPC::Request *rpc; + + status_t result; + int attempts = 0; + do { + result = fServer->SendCallAsync(fBuilder.Request(), &rpl, &rpc); + if (result == B_NO_MEMORY) + return result; + else if (result != B_OK) { + fServer->Repair(); + continue; + } + + result = fServer->WaitCall(rpc); + if (result != B_OK) { + fServer->CancelCall(rpc); + delete rpc; + + fServer->Repair(); + } + } while (result != B_OK && attempts++ < kRetryLimit); + + return fReply.SetTo(rpl); +} + + void Request::Reset() { diff --git a/src/add-ons/kernel/file_systems/nfs4/Request.h b/src/add-ons/kernel/file_systems/nfs4/Request.h index 60dc99b8f5..317bd3fbd4 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Request.h +++ b/src/add-ons/kernel/file_systems/nfs4/Request.h @@ -25,12 +25,15 @@ public: void Reset(); private: - status_t _TrySend(); + status_t _SendUDP(); + status_t _SendTCP(); RPC::Server* fServer; RequestBuilder fBuilder; ReplyInterpreter fReply; + + static const int kRetryLimit = 5; }; From e6e9b107de2da882cfbc24625942ec90f87cd530 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Mon, 11 Jun 2012 22:27:37 +0200 Subject: [PATCH 043/252] nfs4: Partial support for servers not providing FileId --- .../kernel/file_systems/nfs4/Filehandle.h | 4 +++ .../kernel/file_systems/nfs4/Filesystem.cpp | 2 +- .../kernel/file_systems/nfs4/Filesystem.h | 4 +-- .../kernel/file_systems/nfs4/Inode.cpp | 36 +++++++++++-------- .../kernel/file_systems/nfs4/InodeIdMap.h | 6 ++-- 5 files changed, 32 insertions(+), 20 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Filehandle.h b/src/add-ons/kernel/file_systems/nfs4/Filehandle.h index 3d66aa6027..1aee36ce29 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Filehandle.h +++ b/src/add-ons/kernel/file_systems/nfs4/Filehandle.h @@ -31,6 +31,7 @@ struct Filehandle { // Unfortunately just a filehandle is not enough even when they are persistent // since OPEN requires both parent filehandle and file name (just like LOOKUP). struct FileInfo { + uint64 fFileId; Filehandle fFH; Filehandle fParent; @@ -74,6 +75,7 @@ Filehandle::operator=(const Filehandle& fh) inline FileInfo::FileInfo() : + fFileId(0), fName(NULL) { } @@ -89,6 +91,7 @@ FileInfo::~FileInfo() inline FileInfo::FileInfo(const FileInfo& fi) : + fFileId(fi.fFileId), fFH(fi.fFH), fParent(fi.fParent), fName(strdup(fi.fName)) @@ -99,6 +102,7 @@ FileInfo::FileInfo(const FileInfo& fi) inline FileInfo& FileInfo::operator=(const FileInfo& fi) { + fFileId = fi.fFileId; fFH = fi.fFH; fParent = fi.fParent; diff --git a/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp b/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp index 6502c0f2f5..dae44132d8 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp @@ -18,7 +18,7 @@ Filesystem::Filesystem() : - fId(0) + fId(1) { } diff --git a/src/add-ons/kernel/file_systems/nfs4/Filesystem.h b/src/add-ons/kernel/file_systems/nfs4/Filesystem.h index d919c269d1..7dac599063 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Filesystem.h +++ b/src/add-ons/kernel/file_systems/nfs4/Filesystem.h @@ -28,7 +28,7 @@ public: inline uint32 FHExpiryType() const; inline RPC::Server* Server(); - inline uint64 GetId(); + inline uint64 AllocFileId(); inline dev_t DevId() const; inline InodeIdMap* InoIdMap(); @@ -56,7 +56,7 @@ Filesystem::Server() inline uint64 -Filesystem::GetId() +Filesystem::AllocFileId() { return atomic_add64(&fId, 1); } diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index a7e92285f7..c0d44ea169 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -48,11 +48,13 @@ Inode::Inode(Filesystem* fs, const FileInfo &fi) if (result != B_OK || count < 1) return; - if (count < 2 || values[1].fAttribute != FATTR4_FILEID) { - // Server does not provide fileid. We need to make something up. - fFileId = fs->GetId(); + if (fi.fFileId == 0) { + if (count < 2 || values[1].fAttribute != FATTR4_FILEID) + fFileId = fs->AllocFileId(); + else + fFileId = values[1].fData.fValue64; } else - fFileId = values[1].fData.fValue64; + fFileId = fi.fFileId; // FATTR4_TYPE is mandatory fType = values[0].fData.fValue32; @@ -124,15 +126,15 @@ Inode::LookUp(const char* name, ino_t* id) if (result != B_OK) return result; - if (count < 1 || values[0].fAttribute != FATTR4_FILEID) { - delete[] values; - return B_UNSUPPORTED; - } - - *id = _FileIdToInoT(values[0].fData.fValue64); + uint64 fileId; + if (count < 1 || values[0].fAttribute != FATTR4_FILEID) + fileId = fFilesystem->AllocFileId(); + else + fileId = values[0].fData.fValue64; delete[] values; - fFilesystem->InoIdMap()->AddEntry(fh, fHandle, name, *id); + *id = _FileIdToInoT(fileId); + fFilesystem->InoIdMap()->AddEntry(fh, fHandle, name, fileId, *id); return B_OK; } @@ -500,15 +502,19 @@ Inode::_ReadDirUp(struct dirent* de, uint32 pos, uint32 size) uint64 fileId; if (count < 1 || values[0].fAttribute != FATTR4_FILEID) { - // Server does not provide fileid. We need to make something up. - fileId = fFilesystem->GetId(); + fileId = fFilesystem->AllocFileId(); } else fileId = values[0].fData.fValue64; return _FillDirEntry(de, _FileIdToInoT(fileId), "..", pos, size); } - +// TODO: Currently inode numbers returned by ReadDir are virtually random. +// Apparently Haiku does not use that information (contrary to inode number +// returned by LookUp) so fixing it can wait until directory caches are +// implemented. +// When directories are cached client should store inode numbers it assigned +// to directroy entries and use them consequently. status_t Inode::ReadDir(void* _buffer, uint32 size, uint32* _count, uint64* cookie) { @@ -558,7 +564,7 @@ Inode::ReadDir(void* _buffer, uint32 size, uint32* _count, uint64* cookie) if (dirents[i].fAttrCount == 1) id = _FileIdToInoT(dirents[i].fAttrs[0].fData.fValue64); else - id = _FileIdToInoT(fFilesystem->GetId()); + id = _FileIdToInoT(fFilesystem->AllocFileId()); const char* name = dirents[i].fName; if (_FillDirEntry(de, id, name, pos, size) == B_BUFFER_OVERFLOW) { diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeIdMap.h b/src/add-ons/kernel/file_systems/nfs4/InodeIdMap.h index 887ab2f98e..bf73f0a9d1 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeIdMap.h +++ b/src/add-ons/kernel/file_systems/nfs4/InodeIdMap.h @@ -19,7 +19,8 @@ class InodeIdMap { public: inline status_t AddEntry(const Filehandle& fh, const Filehandle& parent, - const char* name, ino_t id); + const char* name, uint64 fileId, + ino_t id); inline status_t GetFileInfo(FileInfo* fi, ino_t id); private: @@ -30,9 +31,10 @@ private: inline status_t InodeIdMap::AddEntry(const Filehandle& fh, const Filehandle& parent, - const char* name, ino_t id) + const char* name, uint64 fileId, ino_t id) { FileInfo fi; + fi.fFileId = fileId; fi.fFH = fh; fi.fParent = parent; fi.fName = strdup(name); From d8a223873f9743816a10660c41da8a3e05c74191 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Mon, 11 Jun 2012 22:43:06 +0200 Subject: [PATCH 044/252] nfs4: Use ACCESS if server does not provide file mode --- .../kernel/file_systems/nfs4/Inode.cpp | 30 +++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index c0d44ea169..6d7af636ae 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -223,14 +223,40 @@ Inode::Stat(struct stat* st) if (count >= next && values[next].fAttribute == FATTR4_MODE) { st->st_mode |= values[next].fData.fValue32; next++; + } else { + // Try to guess using ACCESS request + request.Reset(); + request.Builder().PutFH(fHandle); + request.Builder().Access(); + result = request.Send(); + if (result != B_OK) + return result; + result = request.Reply().PutFH(); + if (result != B_OK) + return result; + uint32 prvl; + result = request.Reply().Access(NULL, &prvl); + if (result != B_OK) + return result; + + if ((prvl & ACCESS4_READ) != 0) + st->st_mode |= S_IRUSR | S_IRGRP | S_IROTH; + + if ((prvl & ACCESS4_MODIFY) != 0) + st->st_mode |= S_IWUSR | S_IWGRP | S_IWOTH; + + if (fType == NF4DIR && (prvl & ACCESS4_LOOKUP) != 0) + st->st_mode |= S_IXUSR | S_IXGRP | S_IXOTH; + + if (fType != NF4DIR && (prvl & ACCESS4_EXECUTE) != 0) + st->st_mode |= S_IXUSR | S_IXGRP | S_IXOTH; } - // TODO: else: get some info from ACCESS if (count >= next && values[next].fAttribute == FATTR4_NUMLINKS) { st->st_nlink = values[next].fData.fValue32; next++; } else - st->st_nlink = 1; // TODO: if !link_support we dont have to ask + st->st_nlink = 1; st->st_uid = 0; st->st_gid = 0; From 0792abe0062dc05163f5873f3753fe74a6e307c6 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Tue, 12 Jun 2012 00:38:07 +0200 Subject: [PATCH 045/252] nfs4: Fix timeout handling code --- .../kernel/file_systems/nfs4/Filesystem.cpp | 15 +++++-- .../kernel/file_systems/nfs4/Inode.cpp | 44 ++++++++++++------- src/add-ons/kernel/file_systems/nfs4/Inode.h | 5 ++- .../kernel/file_systems/nfs4/RPCServer.cpp | 3 ++ .../kernel/file_systems/nfs4/RPCServer.h | 3 ++ .../kernel/file_systems/nfs4/Request.cpp | 9 +++- .../file_systems/nfs4/kernel_interface.cpp | 6 +++ 7 files changed, 63 insertions(+), 22 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp b/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp index dae44132d8..1ac6ddcb15 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp @@ -135,9 +135,10 @@ Filesystem::GetInode(ino_t id, Inode** _inode) if (result != B_OK) return result; - Inode* inode = new(std::nothrow)Inode(this, fi); - if (inode == NULL) - return B_NO_MEMORY; + Inode* inode; + result = Inode::CreateInode(this, fi, &inode); + if (result != B_OK) + return result; *_inode = inode; return B_OK; @@ -151,6 +152,12 @@ Filesystem::CreateRootInode() fi.fFH = fRootFH; fi.fParent = fRootFH; fi.fName = strdup("/"); - return new(std::nothrow)Inode(this, fi); + + Inode* inode; + status_t result = Inode::CreateInode(this, fi, &inode); + if (result == B_OK) + return inode; + else + return NULL; } diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index 6d7af636ae..71ec69a34d 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -15,51 +15,65 @@ #include "Request.h" +Inode::Inode() +{ +} + + // Creating Inode object from Filehandle probably is not a good idea when // filehandles are volatile. -Inode::Inode(Filesystem* fs, const FileInfo &fi) - : - fHandle(fi.fFH), - fFilesystem(fs), - fParentFH(fi.fParent), - fName(strdup(fi.fName)) +status_t +Inode::CreateInode(Filesystem* fs, const FileInfo &fi, Inode** _inode) { - Request request(fFilesystem->Server()); + Inode* inode = new(std::nothrow) Inode; + if (inode == NULL) + return B_NO_MEMORY; + + inode->fHandle = fi.fFH; + inode->fFilesystem = fs; + inode->fParentFH = fi.fParent; + inode->fName = strdup(fi.fName); + + Request request(fs->Server()); RequestBuilder& req = request.Builder(); - req.PutFH(fHandle); + req.PutFH(inode->fHandle); Attribute attr[] = { FATTR4_TYPE, FATTR4_FILEID }; req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); status_t result = request.Send(); if (result != B_OK) - return; + return result; ReplyInterpreter& reply = request.Reply(); result = reply.PutFH(); if (result != B_OK) - return; + return result; AttrValue* values; uint32 count; result = reply.GetAttr(&values, &count); if (result != B_OK || count < 1) - return; + return result; if (fi.fFileId == 0) { if (count < 2 || values[1].fAttribute != FATTR4_FILEID) - fFileId = fs->AllocFileId(); + inode->fFileId = fs->AllocFileId(); else - fFileId = values[1].fData.fValue64; + inode->fFileId = values[1].fData.fValue64; } else - fFileId = fi.fFileId; + inode->fFileId = fi.fFileId; // FATTR4_TYPE is mandatory - fType = values[0].fData.fValue32; + inode->fType = values[0].fData.fValue32; delete[] values; + + *_inode = inode; + + 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 6813ed46ac..36f6405fbb 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -26,7 +26,8 @@ struct OpenFileCookie { class Inode { public: - Inode(Filesystem* fs, const FileInfo& fi); + static status_t CreateInode(Filesystem* fs, const FileInfo& fi, + Inode** inode); ~Inode(); inline ino_t ID() const; @@ -47,6 +48,8 @@ public: uint32* count, uint64* cookie); private: + Inode(); + status_t _ReadDirOnce(DirEntry** dirents, uint32* count, uint64* cookie, bool* eof); status_t _FillDirEntry(struct dirent* de, ino_t id, diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp b/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp index 329daec6ec..41de2cbcb1 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp @@ -150,6 +150,8 @@ Server::SendCallAsync(Call* call, Reply** reply, Request** request) call->SetXID(xid); req->fXID = xid; req->fReply = reply; + req->fEvent.Init(&req->fEvent, NULL); + req->fDone = false; req->fNext = NULL; fRequests.AddRequest(req); @@ -227,6 +229,7 @@ Server::_Listener() Request* req = fRequests.FindRequest(reply->GetXID()); if (req != NULL) { *req->fReply = reply; + req->fDone = true; req->fEvent.NotifyAll(); } else delete reply; diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCServer.h b/src/add-ons/kernel/file_systems/nfs4/RPCServer.h index 8241cd6ee3..3ba5c7fa29 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RPCServer.h +++ b/src/add-ons/kernel/file_systems/nfs4/RPCServer.h @@ -22,6 +22,7 @@ namespace RPC { struct Request { uint32 fXID; ConditionVariable fEvent; + bool fDone; Reply** fReply; Request* fNext; @@ -86,6 +87,8 @@ private: inline status_t Server::WaitCall(Request* request, bigtime_t time) { + if (request->fDone) + return B_OK; return request->fEvent.Wait(B_RELATIVE_TIMEOUT, time); } diff --git a/src/add-ons/kernel/file_systems/nfs4/Request.cpp b/src/add-ons/kernel/file_systems/nfs4/Request.cpp index 125bdc9aa8..fdf9871086 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Request.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Request.cpp @@ -35,10 +35,15 @@ Request::_SendUDP() result = fServer->WaitCall(rpc); if (result != B_OK) { int attempts = 1; - while (result != B_OK && attempts++ < kRetryLimit) + while (result != B_OK && attempts++ < kRetryLimit) { result = fServer->ResendCallAsync(fBuilder.Request(), rpc); + if (result != B_OK) + return result; - if (attempts == kRetryLimit) { + result = fServer->WaitCall(rpc); + } + + if (result != B_OK) { fServer->CancelCall(rpc); delete rpc; return result; 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 d34d25e0df..8951a2b0f5 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -50,6 +50,12 @@ nfs4_mount(fs_volume* volume, const char* device, uint32 flags, } Inode* inode = fs->CreateRootInode(); + if (inode == NULL) { + delete fs; + gRPCServerManager->Release(server); + + return B_IO_ERROR; + } volume->private_volume = fs; volume->ops = &gNFSv4VolumeOps; From 96e3dbc2d0e58ab0798ea433242696d982057fb6 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Tue, 12 Jun 2012 00:59:01 +0200 Subject: [PATCH 046/252] nfs4: Let stat() retrieve access, change, etc dates --- .../kernel/file_systems/nfs4/Inode.cpp | 28 +++++++- .../file_systems/nfs4/ReplyInterpreter.cpp | 66 +++++++++++++++++++ .../file_systems/nfs4/ReplyInterpreter.h | 4 ++ 3 files changed, 97 insertions(+), 1 deletion(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index 71ec69a34d..6e6d77373d 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -206,7 +206,9 @@ Inode::Stat(struct stat* st) req.PutFH(fHandle); - Attribute attr[] = { FATTR4_SIZE, FATTR4_MODE, FATTR4_NUMLINKS }; + Attribute attr[] = { FATTR4_SIZE, FATTR4_MODE, FATTR4_NUMLINKS, + FATTR4_TIME_ACCESS, FATTR4_TIME_CREATE, + FATTR4_TIME_METADATA, FATTR4_TIME_MODIFY }; req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); status_t result = request.Send(); @@ -272,6 +274,30 @@ Inode::Stat(struct stat* st) } else st->st_nlink = 1; + if (count >= next && values[next].fAttribute == FATTR4_TIME_ACCESS) { + memcpy(&st->st_atim, values[next].fData.fPointer, sizeof(timespec)); + next++; + } else + memset(&st->st_atim, 0, sizeof(timespec)); + + if (count >= next && values[next].fAttribute == FATTR4_TIME_CREATE) { + memcpy(&st->st_crtim, values[next].fData.fPointer, sizeof(timespec)); + next++; + } else + memset(&st->st_crtim, 0, sizeof(timespec)); + + if (count >= next && values[next].fAttribute == FATTR4_TIME_METADATA) { + memcpy(&st->st_ctim, values[next].fData.fPointer, sizeof(timespec)); + next++; + } else + memset(&st->st_ctim, 0, sizeof(timespec)); + + if (count >= next && values[next].fAttribute == FATTR4_TIME_MODIFY) { + memcpy(&st->st_mtim, values[next].fData.fPointer, sizeof(timespec)); + next++; + } else + memset(&st->st_mtim, 0, sizeof(timespec)); + st->st_uid = 0; st->st_gid = 0; diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp index 5782247493..d38f6d542f 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp @@ -14,6 +14,20 @@ #include +AttrValue::AttrValue() + : + fFreePointer(false) +{ +} + + +AttrValue::~AttrValue() +{ + if (fFreePointer) + free(fData.fPointer); +} + + DirEntry::DirEntry() : fName(NULL), @@ -327,6 +341,58 @@ ReplyInterpreter::_DecodeAttrs(XDR::ReadStream& str, AttrValue** attrs, current++; } + if (sIsAttrSet(FATTR4_TIME_ACCESS, bitmap, bcount)) { + values[current].fAttribute = FATTR4_TIME_ACCESS; + values[current].fFreePointer = true; + + struct timespec ts; + ts.tv_sec = static_cast(stream.GetHyper()); + ts.tv_nsec = static_cast(stream.GetUInt()); + + values[current].fData.fPointer = malloc(sizeof(ts)); + memcpy(values[current].fData.fPointer, &ts, sizeof(ts)); + current++; + } + + if (sIsAttrSet(FATTR4_TIME_CREATE, bitmap, bcount)) { + values[current].fAttribute = FATTR4_TIME_CREATE; + values[current].fFreePointer = true; + + struct timespec ts; + ts.tv_sec = static_cast(stream.GetHyper()); + ts.tv_nsec = static_cast(stream.GetUInt()); + + values[current].fData.fPointer = malloc(sizeof(ts)); + memcpy(values[current].fData.fPointer, &ts, sizeof(ts)); + current++; + } + + if (sIsAttrSet(FATTR4_TIME_METADATA, bitmap, bcount)) { + values[current].fAttribute = FATTR4_TIME_METADATA; + values[current].fFreePointer = true; + + struct timespec ts; + ts.tv_sec = static_cast(stream.GetHyper()); + ts.tv_nsec = static_cast(stream.GetUInt()); + + values[current].fData.fPointer = malloc(sizeof(ts)); + memcpy(values[current].fData.fPointer, &ts, sizeof(ts)); + current++; + } + + if (sIsAttrSet(FATTR4_TIME_MODIFY, bitmap, bcount)) { + values[current].fAttribute = FATTR4_TIME_MODIFY; + values[current].fFreePointer = true; + + struct timespec ts; + ts.tv_sec = static_cast(stream.GetHyper()); + ts.tv_nsec = static_cast(stream.GetUInt()); + + values[current].fData.fPointer = malloc(sizeof(ts)); + memcpy(values[current].fData.fPointer, &ts, sizeof(ts)); + current++; + } + delete[] bitmap; *count = attr_count; diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h index e0c56f6297..1531fe73e2 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h @@ -16,7 +16,11 @@ struct AttrValue { + AttrValue(); + ~AttrValue(); + uint8 fAttribute; + bool fFreePointer; union { uint32 fValue32; uint64 fValue64; From 6ee3ed0f6f3da3a9d930837b75ab4e6416ce8cd8 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Wed, 13 Jun 2012 01:43:52 +0200 Subject: [PATCH 047/252] nfs4: Add per server NFS4 objects RPC::Server is now able to store RPC programs data. NFS4Server objects are currently used mainly for managing client id. --- .../kernel/file_systems/nfs4/Filesystem.h | 12 ++- .../kernel/file_systems/nfs4/Inode.cpp | 43 +++-------- src/add-ons/kernel/file_systems/nfs4/Inode.h | 2 +- src/add-ons/kernel/file_systems/nfs4/Jamfile | 1 + .../kernel/file_systems/nfs4/NFS4Server.cpp | 74 +++++++++++++++++++ .../kernel/file_systems/nfs4/NFS4Server.h | 44 +++++++++++ .../kernel/file_systems/nfs4/RPCServer.cpp | 9 ++- .../kernel/file_systems/nfs4/RPCServer.h | 28 ++++++- .../file_systems/nfs4/kernel_interface.cpp | 10 ++- 9 files changed, 184 insertions(+), 39 deletions(-) create mode 100644 src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp create mode 100644 src/add-ons/kernel/file_systems/nfs4/NFS4Server.h diff --git a/src/add-ons/kernel/file_systems/nfs4/Filesystem.h b/src/add-ons/kernel/file_systems/nfs4/Filesystem.h index 7dac599063..380cbe42ec 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Filesystem.h +++ b/src/add-ons/kernel/file_systems/nfs4/Filesystem.h @@ -11,7 +11,7 @@ #include "InodeIdMap.h" #include "NFS4Defs.h" -#include "RPCServer.h" +#include "NFS4Server.h" class Inode; @@ -27,7 +27,10 @@ public: Inode* CreateRootInode(); inline uint32 FHExpiryType() const; + inline RPC::Server* Server(); + inline NFS4Server* NFSServer(); + inline uint64 AllocFileId(); inline dev_t DevId() const; @@ -55,6 +58,13 @@ Filesystem::Server() } +inline NFS4Server* +Filesystem::NFSServer() +{ + return reinterpret_cast(fServer->PrivateData()); +} + + inline uint64 Filesystem::AllocFileId() { diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index 6e6d77373d..9fc701fa5c 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -83,9 +83,6 @@ Inode::~Inode() } -// filesystems that do not provide fileid are currently unsupported -// client will have to be able to create its own mapping between file names -// and made up IDs status_t Inode::LookUp(const char* name, ino_t* id) { @@ -309,39 +306,16 @@ Inode::Stat(struct stat* st) status_t Inode::Open(int mode, OpenFileCookie* cookie) { - cookie->fSeq = 0; + cookie->fClientId = fFilesystem->NFSServer()->ClientId(); Request request(fFilesystem->Server()); - request.Builder().SetClientID(fFilesystem->Server()); - - status_t result = request.Send(); - if (result != B_OK) - return result; - - uint64 id, ver; - result = request.Reply().SetClientID(&id, &ver); - if (result != B_OK) - return result; - - request.Reset(); - request.Builder().SetClientIDConfirm(id, ver); - - result = request.Send(); - if (result != B_OK) - return result; - - result = request.Reply().SetClientIDConfirm(); - if (result != B_OK) - return result; - - request.Reset(); RequestBuilder& req = request.Builder(); req.PutFH(fParentFH); - req.Open(cookie->fSeq, OPEN4_SHARE_ACCESS_READ, id, OPEN4_NOCREATE, fName); - cookie->fSeq++; + req.Open(fFilesystem->NFSServer()->SequenceId(), OPEN4_SHARE_ACCESS_READ, + cookie->fClientId, OPEN4_NOCREATE, fName); - result = request.Send(); + status_t result = request.Send(); if (result != B_OK) return result; @@ -359,8 +333,8 @@ Inode::Open(int mode, OpenFileCookie* cookie) if (confirm) { request.Reset(); req.PutFH(fHandle); - req.OpenConfirm(cookie->fSeq, cookie->fStateId, cookie->fStateSeq); - cookie->fSeq++; + req.OpenConfirm(fFilesystem->NFSServer()->SequenceId(), + cookie->fStateId, cookie->fStateSeq); result = request.Send(); if (result != B_OK) @@ -386,7 +360,8 @@ Inode::Close(OpenFileCookie* cookie) RequestBuilder& req = request.Builder(); req.PutFH(fHandle); - req.Close(cookie->fSeq, cookie->fStateId, cookie->fStateSeq); + req.Close(fFilesystem->NFSServer()->SequenceId(), cookie->fStateId, + cookie->fStateSeq); status_t result = request.Send(); if (result != B_OK) @@ -402,6 +377,8 @@ Inode::Close(OpenFileCookie* cookie) if (result != B_OK) return result; + fFilesystem->NFSServer()->ReleaseCID(cookie->fClientId); + 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 36f6405fbb..0e99e7cb72 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -19,9 +19,9 @@ struct OpenFileCookie { + uint64 fClientId; uint32 fStateId[3]; uint32 fStateSeq; - uint32 fSeq; }; class Inode { diff --git a/src/add-ons/kernel/file_systems/nfs4/Jamfile b/src/add-ons/kernel/file_systems/nfs4/Jamfile index e1b56c1186..a5ac6260ff 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Jamfile +++ b/src/add-ons/kernel/file_systems/nfs4/Jamfile @@ -7,6 +7,7 @@ KernelAddon nfs4 : Filesystem.cpp Inode.cpp kernel_interface.cpp + NFS4Server.cpp ReplyInterpreter.cpp Request.cpp RequestBuilder.cpp diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp new file mode 100644 index 0000000000..8284b85b7f --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp @@ -0,0 +1,74 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ + + +#include "NFS4Server.h" +#include "Request.h" + + +NFS4Server::NFS4Server(RPC::Server* serv) + : + fCIDUseCount(0), + fSequenceId(0), + fServer(serv) +{ + mutex_init(&fLock, NULL); +} + + +NFS4Server::~NFS4Server() +{ + mutex_destroy(&fLock); +} + + +uint64 +NFS4Server::ClientId(uint64 prevId, bool forceNew) +{ + mutex_lock(&fLock); + if ((forceNew && fClientId == prevId) || fCIDUseCount == 0) { + Request request(fServer); + request.Builder().SetClientID(fServer); + + status_t result = request.Send(); + if (result != B_OK) + goto out_unlock; + + uint64 ver; + result = request.Reply().SetClientID(&fClientId, &ver); + if (result != B_OK) + goto out_unlock; + + request.Reset(); + request.Builder().SetClientIDConfirm(fClientId, ver); + + result = request.Send(); + if (result != B_OK) + goto out_unlock; + + result = request.Reply().SetClientIDConfirm(); + if (result != B_OK) + goto out_unlock; + } + + fCIDUseCount++; + +out_unlock: + mutex_unlock(&fLock); + return fClientId; +} + + +void +NFS4Server::ReleaseCID(uint64 cid) +{ + mutex_lock(&fLock); + fCIDUseCount--; + mutex_unlock(&fLock); +} + diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h new file mode 100644 index 0000000000..80c43b6237 --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h @@ -0,0 +1,44 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ +#ifndef NFS4SERVER_H +#define NFS4SERVER_H + + +#include + +#include "RPCServer.h" + + +class NFS4Server : public RPC::ProgramData { +public: + NFS4Server(RPC::Server* serv); + virtual ~NFS4Server(); + + uint64 ClientId(uint64 prevId = 0, bool forceNew = false); + void ReleaseCID(uint64 cid); + + inline uint32 SequenceId(); +private: + uint64 fClientId; + uint32 fCIDUseCount; + mutex fLock; + + vint32 fSequenceId; + + RPC::Server* fServer; +}; + +uint32 +NFS4Server::SequenceId() +{ + return static_cast(atomic_add(&fSequenceId, 1)); +} + + +#endif // NFS4SERVER_H + diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp b/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp index 41de2cbcb1..8edb3d84d1 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp @@ -77,6 +77,7 @@ Server::Server(Connection* conn, ServerAddress* addr) : fConnection(conn), fAddress(addr), + fPrivateData(NULL), fXID(rand() << 1) { _StartListening(); @@ -85,6 +86,8 @@ Server::Server(Connection* conn, ServerAddress* addr) Server::~Server() { + delete fPrivateData; + fThreadCancel = true; fConnection->Disconnect(); interrupt_thread(fThread); @@ -200,7 +203,7 @@ Server::Repair() uint32 Server::_GetXID() { - return (uint32)atomic_add(&fXID, 1); + return static_cast(atomic_add(&fXID, 1)); } @@ -262,7 +265,8 @@ ServerManager::~ServerManager() status_t -ServerManager::Acquire(Server** pserv, uint32 ip, uint16 port, Transport proto) +ServerManager::Acquire(Server** pserv, uint32 ip, uint16 port, Transport proto, + ProgramData* (*createPriv)(Server*)) { status_t result; @@ -301,6 +305,7 @@ ServerManager::Acquire(Server** pserv, uint32 ip, uint16 port, Transport proto) delete conn; return B_NO_MEMORY; } + node->fServer->SetPrivateData(createPriv(node->fServer)); node->fRefCount = 1; node->fLeft = node->fRight = NULL; diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCServer.h b/src/add-ons/kernel/file_systems/nfs4/RPCServer.h index 3ba5c7fa29..c45765e63e 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RPCServer.h +++ b/src/add-ons/kernel/file_systems/nfs4/RPCServer.h @@ -43,6 +43,11 @@ private: }; +class ProgramData { +public: + virtual ~ProgramData() { } +}; + class Server { public: Server(Connection* conn, @@ -63,6 +68,9 @@ public: inline const ServerAddress& ID() const; inline ServerAddress LocalID() const; + inline ProgramData* PrivateData(); + inline void SetPrivateData(ProgramData* priv); + private: inline uint32 _GetXID(); @@ -79,6 +87,8 @@ private: Connection* fConnection; const ServerAddress* fAddress; + ProgramData* fPrivateData; + vint32 fXID; static const bigtime_t kWaitTime = 1000000; }; @@ -118,6 +128,21 @@ Server::LocalID() const } +inline ProgramData* +Server::PrivateData() +{ + return fPrivateData; +} + + +inline void +Server::SetPrivateData(ProgramData* priv) +{ + delete fPrivateData; + fPrivateData = priv; +} + + struct ServerNode { ServerAddress fID; Server* fServer; @@ -133,7 +158,8 @@ public: ~ServerManager(); status_t Acquire(Server** pserv, uint32 ip, uint16 port, - Transport proto); + Transport proto, + ProgramData* (*createPriv)(Server*)); void Release(Server* serv); private: 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 8951a2b0f5..ed922ad062 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -28,6 +28,13 @@ dprintf(const char* format, ...); RPC::ServerManager* gRPCServerManager; +static RPC::ProgramData* +sCreateNFS4Server(RPC::Server* serv) +{ + return new NFS4Server(serv); +} + + static status_t nfs4_mount(fs_volume* volume, const char* device, uint32 flags, const char* args, ino_t* _rootVnodeID) @@ -36,7 +43,8 @@ nfs4_mount(fs_volume* volume, const char* device, uint32 flags, RPC::Server *server; // hardcoded ip 192.168.1.70 - result = gRPCServerManager->Acquire(&server, 0xc0a80146, 2049, ProtocolUDP); + result = gRPCServerManager->Acquire(&server, 0xc0a80146, 2049, ProtocolUDP, + sCreateNFS4Server); if (result != B_OK) return result; From 27a291de54f614424392492632152093a84e2810 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Wed, 13 Jun 2012 02:38:51 +0200 Subject: [PATCH 048/252] nfs4: Renew all owned and used leases --- .../kernel/file_systems/nfs4/NFS4Defs.h | 1 + .../kernel/file_systems/nfs4/NFS4Server.cpp | 108 ++++++++++++++++++ .../kernel/file_systems/nfs4/NFS4Server.h | 10 ++ .../file_systems/nfs4/ReplyInterpreter.cpp | 6 + .../file_systems/nfs4/ReplyInterpreter.h | 8 ++ .../file_systems/nfs4/RequestBuilder.cpp | 21 +++- .../kernel/file_systems/nfs4/RequestBuilder.h | 3 +- 7 files changed, 154 insertions(+), 3 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h index 8ded674387..c8b71121e8 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h @@ -33,6 +33,7 @@ enum Opcode { OpPutRootFH = 24, OpRead = 25, OpReadDir = 26, + OpRenew = 30, OpSetClientID = 35, OpSetClientIDConfirm = 36 }; diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp index 8284b85b7f..3bf1b5d3b5 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp @@ -13,6 +13,8 @@ NFS4Server::NFS4Server(RPC::Server* serv) : + fThreadCancel(true), + fLeaseTime(0), fCIDUseCount(0), fSequenceId(0), fServer(serv) @@ -23,6 +25,12 @@ NFS4Server::NFS4Server(RPC::Server* serv) NFS4Server::~NFS4Server() { + fThreadCancel = true; + fCIDUseCount = 0; + interrupt_thread(fThread); + status_t result; + wait_for_thread(fThread, &result); + mutex_destroy(&fLock); } @@ -54,6 +62,8 @@ NFS4Server::ClientId(uint64 prevId, bool forceNew) result = request.Reply().SetClientIDConfirm(); if (result != B_OK) goto out_unlock; + + _StartRenewing(); } fCIDUseCount++; @@ -72,3 +82,101 @@ NFS4Server::ReleaseCID(uint64 cid) mutex_unlock(&fLock); } + +status_t +NFS4Server::_GetLeaseTime() +{ + Request request(fServer); + request.Builder().PutRootFH(); + Attribute attr[] = { FATTR4_LEASE_TIME }; + request.Builder().GetAttr(attr, sizeof(attr) / sizeof(Attribute)); + + status_t result = request.Send(); + if (result != B_OK) + return result; + + ReplyInterpreter& reply = request.Reply(); + + result = reply.PutRootFH(); + if (result != B_OK) + return result; + + AttrValue* values; + uint32 count; + result = reply.GetAttr(&values, &count); + if (result != B_OK) + return result; + + // FATTR4_LEASE_TIM is mandatory + if (count < 1 || values[0].fAttribute != FATTR4_LEASE_TIME) { + delete[] values; + return B_BAD_VALUE; + } + + fLeaseTime = values[0].fData.fValue32 * 1000000; + + return B_OK; +} + + +status_t +NFS4Server::_StartRenewing() +{ + if (!fThreadCancel) + return B_OK; + + + if (fLeaseTime == 0) { + status_t result = _GetLeaseTime(); + if (result != B_OK) + return result; + } + + fThreadCancel = false; + fThread = spawn_kernel_thread(&NFS4Server::_RenewalThreadStart, + "NFSv4 Renewal", B_NORMAL_PRIORITY, this); + if (fThread < B_OK) + return fThread; + + status_t result = resume_thread(fThread); + if (result != B_OK) { + kill_thread(fThread); + return result; + } + + return B_OK; +} + + +status_t +NFS4Server::_Renewal() +{ + while (!fThreadCancel) { + // TODO: operations like OPEN, READ, CLOSE, etc also renew leases + snooze_etc(fLeaseTime - 2, B_SYSTEM_TIMEBASE, B_RELATIVE_TIMEOUT + | B_CAN_INTERRUPT); + mutex_lock(&fLock); + if (fCIDUseCount == 0) { + fThreadCancel = true; + mutex_unlock(&fLock); + return B_OK; + } + + Request request(fServer); + request.Builder().Renew(fClientId); + request.Send(); + + mutex_unlock(&fLock); + } + + return B_OK; +} + + +status_t +NFS4Server::_RenewalThreadStart(void* ptr) +{ + NFS4Server* server = reinterpret_cast(ptr); + return server->_Renewal(); +} + diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h index 80c43b6237..a66c3463bf 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h @@ -24,6 +24,16 @@ public: inline uint32 SequenceId(); private: + status_t _GetLeaseTime(); + + status_t _StartRenewing(); + status_t _Renewal(); + static status_t _RenewalThreadStart(void* ptr); + thread_id fThread; + bool fThreadCancel; + + uint32 fLeaseTime; + uint64 fClientId; uint32 fCIDUseCount; mutex fLock; diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp index d38f6d542f..ece60c05c8 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp @@ -323,6 +323,12 @@ ReplyInterpreter::_DecodeAttrs(XDR::ReadStream& str, AttrValue** attrs, current++; } + if (sIsAttrSet(FATTR4_LEASE_TIME, bitmap, bcount)) { + values[current].fAttribute = FATTR4_LEASE_TIME; + values[current].fData.fValue32 = stream.GetUInt(); + current++; + } + if (sIsAttrSet(FATTR4_FILEID, bitmap, bcount)) { values[current].fAttribute = FATTR4_FILEID; values[current].fData.fValue64 = stream.GetUHyper(); diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h index 1531fe73e2..c513b81ca7 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h @@ -58,6 +58,7 @@ public: status_t Read(void* buffer, uint32* size, bool* eof); status_t ReadDir(uint64* cookie, DirEntry** dirents, uint32* count, bool* eof); + inline status_t Renew(); status_t SetClientID(uint64* clientid, uint64* verifier); inline status_t SetClientIDConfirm(); @@ -125,6 +126,13 @@ ReplyInterpreter::PutRootFH() } +inline status_t +ReplyInterpreter::Renew() +{ + return _OperationError(OpRenew); +} + + inline status_t ReplyInterpreter::SetClientIDConfirm() { diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp index 414322fd3a..b7dc398eba 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp @@ -262,7 +262,7 @@ RequestBuilder::Read(const uint32* id, uint32 stateSeq, uint64 pos, uint32 len) status_t RequestBuilder::ReadDir(uint32 count, uint64* cookie, Attribute* attrs, - uint32 attr_count) + uint32 attrCount) { (void)count; @@ -278,7 +278,24 @@ RequestBuilder::ReadDir(uint32 count, uint64* cookie, Attribute* attrs, // consider predicting this values basing on count or buffer size fRequest->Stream().AddUInt(0x2000); fRequest->Stream().AddUInt(0x8000); - _AttrBitmap(fRequest->Stream(), attrs, attr_count); + _AttrBitmap(fRequest->Stream(), attrs, attrCount); + + fOpCount++; + + return B_OK; +} + + +status_t +RequestBuilder::Renew(uint64 clientId) +{ + if (fProcedure != ProcCompound) + return B_BAD_VALUE; + if (fRequest == NULL) + return B_NO_MEMORY; + + fRequest->Stream().AddUInt(OpRenew); + fRequest->Stream().AddUHyper(clientId); fOpCount++; diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h index 86f5070e71..130c053511 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h @@ -40,7 +40,8 @@ public: status_t Read(const uint32* id, uint32 stateSeq, uint64 pos, uint32 len); status_t ReadDir(uint32 count, uint64* cookie, - Attribute* attrs, uint32 attr_count); + Attribute* attrs, uint32 attrCount); + status_t Renew(uint64 clientId); status_t SetClientID(const RPC::Server* serv); status_t SetClientIDConfirm(uint64 id, uint64 ver); From f2da914d39a0dd3e6819bd7ddca4c4f95f9b9253 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Wed, 13 Jun 2012 03:16:08 +0200 Subject: [PATCH 049/252] nfs4: Add read_symlink() hook --- .../kernel/file_systems/nfs4/Inode.cpp | 30 +++++++++++++++++++ src/add-ons/kernel/file_systems/nfs4/Inode.h | 1 + .../kernel/file_systems/nfs4/NFS4Defs.h | 1 + .../file_systems/nfs4/ReplyInterpreter.cpp | 13 ++++++++ .../file_systems/nfs4/ReplyInterpreter.h | 1 + .../file_systems/nfs4/RequestBuilder.cpp | 16 ++++++++++ .../kernel/file_systems/nfs4/RequestBuilder.h | 1 + .../file_systems/nfs4/kernel_interface.cpp | 11 ++++++- 8 files changed, 73 insertions(+), 1 deletion(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index 9fc701fa5c..f11780ac9a 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -151,6 +151,36 @@ Inode::LookUp(const char* name, ino_t* id) } +status_t +Inode::ReadLink(void* buffer, size_t* length) +{ + if (fType != NF4LNK) + return B_BAD_VALUE; + + Request request(fFilesystem->Server()); + RequestBuilder& req = request.Builder(); + + req.PutFH(fHandle); + req.ReadLink(); + + status_t result = request.Send(); + if (result != B_OK) + return result; + + ReplyInterpreter& reply = request.Reply(); + + result = reply.PutFH(); + if (result != B_OK) + return result; + + uint32 size; + result = reply.ReadLink(buffer, &size, *length); + *length = static_cast(size); + + return result; +} + + status_t Inode::Access(int mode) { diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h b/src/add-ons/kernel/file_systems/nfs4/Inode.h index 0e99e7cb72..43fb9bdef3 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -35,6 +35,7 @@ public: inline const char* Name() const; status_t LookUp(const char* name, ino_t* id); + status_t ReadLink(void* buffer, size_t* length); status_t Access(int mode); status_t Stat(struct stat* st); diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h index c8b71121e8..5dbe383151 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h @@ -33,6 +33,7 @@ enum Opcode { OpPutRootFH = 24, OpRead = 25, OpReadDir = 26, + OpReadLink = 27, OpRenew = 30, OpSetClientID = 35, OpSetClientIDConfirm = 36 diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp index ece60c05c8..f7b62600d0 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp @@ -257,6 +257,19 @@ ReplyInterpreter::ReadDir(uint64* cookie, DirEntry** dirents, uint32* _count, } +status_t +ReplyInterpreter::ReadLink(void* buffer, uint32* size, uint32 maxSize) +{ + status_t res = _OperationError(OpReadLink); + if (res != B_OK) + return res; + + const void* ptr = fReply->Stream().GetOpaque(size); + memcpy(buffer, ptr, min_c(*size, maxSize)); + + return fReply->Stream().IsEOF() ? B_BAD_VALUE : B_OK; +} + status_t ReplyInterpreter::SetClientID(uint64* clientid, uint64* verifier) { diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h index c513b81ca7..4e8ae6e4f6 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h @@ -58,6 +58,7 @@ public: status_t Read(void* buffer, uint32* size, bool* eof); status_t ReadDir(uint64* cookie, DirEntry** dirents, uint32* count, bool* eof); + status_t ReadLink(void* buffer, uint32* size, uint32 maxSize); inline status_t Renew(); status_t SetClientID(uint64* clientid, uint64* verifier); inline status_t SetClientIDConfirm(); diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp index b7dc398eba..d361b861d6 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp @@ -286,6 +286,22 @@ RequestBuilder::ReadDir(uint32 count, uint64* cookie, Attribute* attrs, } +status_t +RequestBuilder::ReadLink() +{ + if (fProcedure != ProcCompound) + return B_BAD_VALUE; + if (fRequest == NULL) + return B_NO_MEMORY; + + fRequest->Stream().AddUInt(OpReadLink); + + fOpCount++; + + return B_OK; +} + + status_t RequestBuilder::Renew(uint64 clientId) { diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h index 130c053511..21e2ecbf77 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h @@ -41,6 +41,7 @@ public: uint64 pos, uint32 len); status_t ReadDir(uint32 count, uint64* cookie, Attribute* attrs, uint32 attrCount); + status_t ReadLink(); status_t Renew(uint64 clientId); status_t SetClientID(const RPC::Server* serv); status_t SetClientIDConfirm(uint64 id, uint64 ver); 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 ed922ad062..bd44f8dffd 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -145,6 +145,15 @@ nfs4_put_vnode(fs_volume* volume, fs_vnode* vnode, bool reenter) } +static status_t +nfs4_read_symlink(fs_volume* volume, fs_vnode* link, char* buffer, + size_t* _bufferSize) +{ + Inode* inode = reinterpret_cast(link->private_node); + return inode->ReadLink(buffer, _bufferSize); +} + + static status_t nfs4_access(fs_volume* volume, fs_vnode* vnode, int mode) { @@ -342,7 +351,7 @@ fs_vnode_ops gNFSv4VnodeOps = { NULL, // fs_deselect() NULL, // fsync() - NULL, // read_link() + nfs4_read_symlink, NULL, // create_symlink() NULL, // link() From 462a54ced847bd3550591ca74ae25143d0444e77 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Wed, 13 Jun 2012 19:38:28 +0200 Subject: [PATCH 050/252] nfs4: Let ReplyInterpreter provide original NFS4 error codes --- .../kernel/file_systems/nfs4/ReplyInterpreter.cpp | 3 ++- .../kernel/file_systems/nfs4/ReplyInterpreter.h | 10 ++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp index f7b62600d0..756e7239a5 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp @@ -46,6 +46,7 @@ DirEntry::~DirEntry() ReplyInterpreter::ReplyInterpreter(RPC::Reply* reply) : + fNFS4Error(NFS4_OK), fReply(reply) { if (reply != NULL) @@ -62,7 +63,7 @@ ReplyInterpreter::~ReplyInterpreter() void ReplyInterpreter::_ParseHeader() { - fReply->Stream().GetUInt(); + fNFS4Error = fReply->Stream().GetUInt(); fReply->Stream().GetOpaque(NULL); fReply->Stream().GetUInt(); } diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h index 4e8ae6e4f6..b3f0901ece 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h @@ -45,6 +45,8 @@ public: inline status_t SetTo(RPC::Reply* reply); inline void Reset(); + inline uint32 NFS4Error(); + status_t Access(uint32* supported, uint32* allowed); status_t Close(); status_t GetAttr(AttrValue** attrs, uint32* count); @@ -72,6 +74,7 @@ private: static status_t _NFS4ErrorToHaiku(uint32 x); + uint32 fNFS4Error; RPC::Reply* fReply; }; @@ -99,6 +102,13 @@ ReplyInterpreter::Reset() } +inline uint32 +ReplyInterpreter::NFS4Error() +{ + return fNFS4Error; +} + + inline status_t ReplyInterpreter::LookUp() { From b268b6f2fc43c0b1f4e5ad527581bb8919543b67 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Wed, 13 Jun 2012 19:44:49 +0200 Subject: [PATCH 051/252] nfs4: Add rest of NFS4 error codes --- .../kernel/file_systems/nfs4/NFS4Defs.h | 72 +++++++++++++++---- 1 file changed, 59 insertions(+), 13 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h index 5dbe383151..b0f9773e49 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h @@ -152,19 +152,65 @@ enum OpenFlags { }; enum Errors { - NFS4_OK = 0, - NFS4ERR_PERM = 1, - NFS4ERR_NOENT = 2, - NFS4ERR_IO = 5, - NFS4ERR_NXIO = 6, - NFS4ERR_ACCESS = 13, - NFS4ERR_EXIST = 17, - NFS4ERR_XDEV = 18, - NFS4ERR_NOTDIR = 20, - NFS4ERR_ISDIR = 21, - NFS4ERR_INVAL = 22, - NFS4ERR_FBIG = 27 - //... + NFS4_OK = 0, + NFS4ERR_PERM = 1, + NFS4ERR_NOENT = 2, + NFS4ERR_IO = 5, + NFS4ERR_NXIO = 6, + NFS4ERR_ACCESS = 13, + NFS4ERR_EXIST = 17, + NFS4ERR_XDEV = 18, + NFS4ERR_NOTDIR = 20, + NFS4ERR_ISDIR = 21, + NFS4ERR_INVAL = 22, + NFS4ERR_FBIG = 27, + NFS4ERR_BADHANDLE = 10001, + NFS4ERR_BAD_COOKIE = 10003, + NFS4ERR_NOTSUPP = 10004, + NFS4ERR_TOOSMALL = 10005, + NFS4ERR_SERVERFAULT = 10006, + NFS4ERR_BADTYPE = 10007, + NFS4ERR_DELAY = 10008, + NFS4ERR_SAME = 10009, + NFS4ERR_DENIED = 10010, + NFS4ERR_EXPIRED = 10011, + NFS4ERR_LOCKED = 10012, + NFS4ERR_GRACE = 10013, + NFS4ERR_FHEXPIRED = 10014, + NFS4ERR_SHARE_DENIED = 10015, + NFS4ERR_WRONGSEC = 10016, + NFS4ERR_CLID_INUSE = 10017, + NFS4ERR_RESOURCE = 10018, + NFS4ERR_MOVED = 10019, + NFS4ERR_NOFILEHANDLE = 10020, + NFS4ERR_MINOR_VERS_MISMATCH = 10021, + NFS4ERR_STALE_CLIENTID = 10022, + NFS4ERR_STALE_STATEID = 10023, + NFS4ERR_OLD_STATEID = 10024, + NFS4ERR_BAD_STATEID = 10025, + NFS4ERR_BAD_SEQID = 10026, + NFS4ERR_NOT_SAME = 10027, + NFS4ERR_LOCK_RANGE = 10028, + NFS4ERR_SYMLINK = 10029, + NFS4ERR_RESTOREFH = 10030, + NFS4ERR_LEASE_MOVED = 10031, + NFS4ERR_ATTRNOTSUPP = 10032, + NFS4ERR_NO_GRACE = 10033, + NFS4ERR_RECLAIM_BAD = 10034, + NFS4ERR_RECLAIM_CONFLICT = 10035, + NFS4ERR_BADXDR = 10036, + NFS4ERR_LOCKS_HELD = 10037, + NFS4ERR_OPENMODE = 10038, + NFS4ERR_BADOWNER = 10039, + NFS4ERR_BADCHAR = 10040, + NFS4ERR_BADNAME = 10041, + NFS4ERR_BAD_RANGE = 10042, + NFS4ERR_LOCK_NOTSUPP = 10043, + NFS4ERR_OP_ILLEGAL = 10044, + NFS4ERR_DEADLOCK = 10045, + NFS4ERR_FILE_OPEN = 10046, + NFS4ERR_ADMIN_REVOKED = 10047, + NFS4ERR_CB_PATH_DOWN = 10048 }; From 8b499ea677bcd1317528c3cadc4b659c88c32888 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Wed, 13 Jun 2012 20:10:47 +0200 Subject: [PATCH 052/252] nfs4: Behave correctly if server is in grace period --- .../kernel/file_systems/nfs4/Inode.cpp | 152 +++++++++++------- .../kernel/file_systems/nfs4/NFS4Server.h | 14 +- 2 files changed, 110 insertions(+), 56 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index f11780ac9a..23a3f70cd9 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -336,32 +336,49 @@ Inode::Stat(struct stat* st) status_t Inode::Open(int mode, OpenFileCookie* cookie) { - cookie->fClientId = fFilesystem->NFSServer()->ClientId(); - - Request request(fFilesystem->Server()); - RequestBuilder& req = request.Builder(); - - req.PutFH(fParentFH); - req.Open(fFilesystem->NFSServer()->SequenceId(), OPEN4_SHARE_ACCESS_READ, - cookie->fClientId, OPEN4_NOCREATE, fName); - - status_t result = request.Send(); - if (result != B_OK) - return result; - - ReplyInterpreter& reply = request.Reply(); - - result = reply.PutFH(); - if (result != B_OK) - return result; - bool confirm; - result = reply.Open(cookie->fStateId, &cookie->fStateSeq, &confirm); - if (result != B_OK) - return result; + status_t result; + do { + cookie->fClientId = fFilesystem->NFSServer()->ClientId(); + + Request request(fFilesystem->Server()); + RequestBuilder& req = request.Builder(); + + req.PutFH(fParentFH); + req.Open(fFilesystem->NFSServer()->SequenceId(), + OPEN4_SHARE_ACCESS_READ, cookie->fClientId, OPEN4_NOCREATE, fName); + + result = request.Send(); + if (result != B_OK) + return result; + + ReplyInterpreter& reply = request.Reply(); + + // 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; + + break; + } while (true); if (confirm) { - request.Reset(); + Request request(fFilesystem->Server()); + + RequestBuilder& req = request.Builder(); + req.PutFH(fHandle); req.OpenConfirm(fFilesystem->NFSServer()->SequenceId(), cookie->fStateId, cookie->fStateSeq); @@ -370,6 +387,8 @@ Inode::Open(int mode, OpenFileCookie* cookie) if (result != B_OK) return result; + ReplyInterpreter& reply = request.Reply(); + result = reply.PutFH(); if (result != B_OK) return result; @@ -386,28 +405,39 @@ Inode::Open(int mode, OpenFileCookie* cookie) status_t Inode::Close(OpenFileCookie* cookie) { - Request request(fFilesystem->Server()); - RequestBuilder& req = request.Builder(); + do { + Request request(fFilesystem->Server()); + RequestBuilder& req = request.Builder(); - req.PutFH(fHandle); - req.Close(fFilesystem->NFSServer()->SequenceId(), cookie->fStateId, - cookie->fStateSeq); + req.PutFH(fHandle); + req.Close(fFilesystem->NFSServer()->SequenceId(), cookie->fStateId, + cookie->fStateSeq); - status_t result = request.Send(); - if (result != B_OK) - return result; + status_t result = request.Send(); + if (result != B_OK) + return result; - ReplyInterpreter& reply = request.Reply(); + ReplyInterpreter& reply = request.Reply(); - result = reply.PutFH(); - if (result != B_OK) - return result; + // 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; + } - result = reply.Close(); - if (result != B_OK) - return result; + result = reply.PutFH(); + if (result != B_OK) + return result; - fFilesystem->NFSServer()->ReleaseCID(cookie->fClientId); + result = reply.Close(); + if (result != B_OK) + return result; + + fFilesystem->NFSServer()->ReleaseCID(cookie->fClientId); + + return B_OK; + } while (true); return B_OK; } @@ -421,28 +451,40 @@ Inode::Read(OpenFileCookie* cookie, off_t pos, void* buffer, size_t* _length) uint32 len = 0; while (size < *_length && !eof) { - Request request(fFilesystem->Server()); - RequestBuilder& req = request.Builder(); + do { + Request request(fFilesystem->Server()); + RequestBuilder& req = request.Builder(); - req.PutFH(fHandle); - req.Read(cookie->fStateId, cookie->fStateSeq, pos + size, - *_length - size); + req.PutFH(fHandle); + req.Read(cookie->fStateId, cookie->fStateSeq, pos + size, + *_length - size); - status_t result = request.Send(); - if (result != B_OK) - return result; + status_t result = request.Send(); + if (result != B_OK) + return result; - ReplyInterpreter& reply = request.Reply(); + ReplyInterpreter& reply = request.Reply(); - result = reply.PutFH(); - if (result != B_OK) - return result; + // 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; + } - result = reply.Read(reinterpret_cast(buffer) + size, &len, &eof); - if (result != B_OK) - return result; + result = reply.PutFH(); + if (result != B_OK) + return result; - size += len; + result = reply.Read(reinterpret_cast(buffer) + size, &len, + &eof); + if (result != B_OK) + return result; + + size += len; + + break; + } while (true); } *_length = size; diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h index a66c3463bf..506b62e5d4 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h @@ -23,6 +23,8 @@ public: void ReleaseCID(uint64 cid); inline uint32 SequenceId(); + + inline uint32 LeaseTime(); private: status_t _GetLeaseTime(); @@ -43,12 +45,22 @@ private: RPC::Server* fServer; }; -uint32 +inline uint32 NFS4Server::SequenceId() { return static_cast(atomic_add(&fSequenceId, 1)); } +inline uint32 +NFS4Server::LeaseTime() +{ + if (fLeaseTime == 0) + _GetLeaseTime(); + + return fLeaseTime; +} + + #endif // NFS4SERVER_H From d1e6b61e2e9523967fce63900692bafe3765d10f Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Wed, 13 Jun 2012 21:37:37 +0200 Subject: [PATCH 053/252] nfs4: Let opened files survive server reboot --- .../kernel/file_systems/nfs4/Inode.cpp | 35 +++++- src/add-ons/kernel/file_systems/nfs4/Inode.h | 16 ++- .../kernel/file_systems/nfs4/NFS4Defs.h | 7 ++ .../kernel/file_systems/nfs4/NFS4Server.cpp | 114 +++++++++++++++++- .../kernel/file_systems/nfs4/NFS4Server.h | 11 ++ .../file_systems/nfs4/RequestBuilder.cpp | 21 +++- .../kernel/file_systems/nfs4/RequestBuilder.h | 6 +- 7 files changed, 193 insertions(+), 17 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index 23a3f70cd9..d1bc6a85e1 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -338,15 +338,23 @@ Inode::Open(int mode, OpenFileCookie* cookie) { bool confirm; status_t result; + + cookie->fHandle = fHandle; + cookie->fMode = mode; + do { cookie->fClientId = fFilesystem->NFSServer()->ClientId(); Request request(fFilesystem->Server()); RequestBuilder& req = request.Builder(); + cookie->fOwnerTime = time(NULL); + cookie->fOwnerTID = find_thread(NULL); + req.PutFH(fParentFH); - req.Open(fFilesystem->NFSServer()->SequenceId(), - OPEN4_SHARE_ACCESS_READ, cookie->fClientId, OPEN4_NOCREATE, fName); + req.Open(CLAIM_NULL, fFilesystem->NFSServer()->SequenceId(), + OPEN4_SHARE_ACCESS_READ, cookie->fClientId, OPEN4_NOCREATE, + cookie->fOwnerTime, cookie->fOwnerTID, fName); result = request.Send(); if (result != B_OK) @@ -374,6 +382,8 @@ Inode::Open(int mode, OpenFileCookie* cookie) break; } while (true); + fFilesystem->NFSServer()->AddOpenFile(cookie); + if (confirm) { Request request(fFilesystem->Server()); @@ -384,18 +394,24 @@ Inode::Open(int mode, OpenFileCookie* cookie) cookie->fStateId, cookie->fStateSeq); result = request.Send(); - if (result != B_OK) + if (result != B_OK) { + fFilesystem->NFSServer()->RemoveOpenFile(cookie); return result; + } ReplyInterpreter& reply = request.Reply(); result = reply.PutFH(); - if (result != B_OK) + if (result != B_OK) { + fFilesystem->NFSServer()->RemoveOpenFile(cookie); return result; + } result = reply.OpenConfirm(&cookie->fStateSeq); - if (result != B_OK) + if (result != B_OK) { + fFilesystem->NFSServer()->RemoveOpenFile(cookie); return result; + } } return B_OK; @@ -405,6 +421,8 @@ Inode::Open(int mode, OpenFileCookie* cookie) status_t Inode::Close(OpenFileCookie* cookie) { + fFilesystem->NFSServer()->RemoveOpenFile(cookie); + do { Request request(fFilesystem->Server()); RequestBuilder& req = request.Builder(); @@ -472,6 +490,13 @@ Inode::Read(OpenFileCookie* cookie, off_t pos, void* buffer, size_t* _length) 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; diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h b/src/add-ons/kernel/file_systems/nfs4/Inode.h index 43fb9bdef3..edbfbece07 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -19,9 +19,19 @@ struct OpenFileCookie { - uint64 fClientId; - uint32 fStateId[3]; - uint32 fStateSeq; + uint64 fClientId; + + uint32 fMode; + + Filehandle fHandle; + uint32 fStateId[3]; + uint32 fStateSeq; + + uint32 fOwnerTime; + uint32 fOwnerTID; + + OpenFileCookie* fNext; + OpenFileCookie* fPrev; }; class Inode { diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h index b0f9773e49..fefe9efb39 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h @@ -146,6 +146,13 @@ enum OpenCreate { OPEN4_CREATE = 1 }; +enum OpenClaim { + CLAIM_NULL = 0, + CLAIM_PREVIOUS = 1, + CLAIM_DELEGATE_CUR = 2, + CLAIM_DELEGATE_PREV = 3 +}; + enum OpenFlags { OPEN4_RESULT_CONFIRM = 2, OPEN4_RESULT_LOCKTYPE_POSIX = 4 diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp index 3bf1b5d3b5..3eab8ab502 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp @@ -7,6 +7,7 @@ */ +#include "Inode.h" #include "NFS4Server.h" #include "Request.h" @@ -17,9 +18,11 @@ NFS4Server::NFS4Server(RPC::Server* serv) fLeaseTime(0), fCIDUseCount(0), fSequenceId(0), + fOpenFiles(NULL), fServer(serv) { mutex_init(&fLock, NULL); + mutex_init(&fOpenLock, NULL); } @@ -32,6 +35,110 @@ NFS4Server::~NFS4Server() wait_for_thread(fThread, &result); mutex_destroy(&fLock); + mutex_destroy(&fOpenLock); +} + + +uint64 +NFS4Server::ServerRebooted(uint64 clientId) +{ + if (clientId != fClientId) + return fClientId; + + fClientId = ClientId(clientId, true); + + // reclaim all open files + mutex_lock(&fOpenLock); + OpenFileCookie* current = fOpenFiles; + while (current != NULL) { + _ReclaimOpen(current); + current = current->fNext; + } + mutex_unlock(&fOpenLock); + + return fClientId; +} + + +status_t +NFS4Server::_ReclaimOpen(OpenFileCookie* cookie) +{ + if (cookie->fClientId == fClientId) + return B_OK; + + cookie->fClientId = fClientId; + + Request request(fServer); + RequestBuilder& req = request.Builder(); + + req.PutFH(cookie->fHandle); + req.Open(CLAIM_PREVIOUS, SequenceId(), OPEN4_SHARE_ACCESS_READ, + cookie->fClientId, OPEN4_NOCREATE, cookie->fOwnerTime, + cookie->fOwnerTID, NULL); + + status_t result = request.Send(); + if (result != B_OK) + return result; + + ReplyInterpreter& reply = request.Reply(); + + result = reply.PutFH(); + if (result != B_OK) + return result; + + bool confirm; + result = reply.Open(cookie->fStateId, &cookie->fStateSeq, &confirm); + if (result != B_OK) + return result; + + if (confirm) { + request.Reset(); + + req.PutFH(cookie->fHandle); + req.OpenConfirm(SequenceId(), cookie->fStateId, cookie->fStateSeq); + + result = request.Send(); + if (result != B_OK) + return result; + + result = reply.PutFH(); + if (result != B_OK) + return result; + + result = reply.OpenConfirm(&cookie->fStateSeq); + if (result != B_OK) + return result; + } + + return B_OK; +} + + +void +NFS4Server::AddOpenFile(OpenFileCookie* cookie) +{ + mutex_lock(&fOpenLock); + cookie->fPrev = NULL; + cookie->fNext = fOpenFiles; + if (fOpenFiles != NULL) + fOpenFiles->fPrev = cookie; + fOpenFiles = cookie; + mutex_unlock(&fOpenLock); +} + + +void +NFS4Server::RemoveOpenFile(OpenFileCookie* cookie) +{ + mutex_lock(&fOpenLock); + if (cookie == fOpenFiles) + fOpenFiles = cookie->fNext; + + if (cookie->fNext) + cookie->fNext->fPrev = cookie->fPrev; + if (cookie->fPrev) + cookie->fPrev->fNext = cookie->fNext; + mutex_unlock(&fOpenLock); } @@ -156,6 +263,9 @@ NFS4Server::_Renewal() snooze_etc(fLeaseTime - 2, B_SYSTEM_TIMEBASE, B_RELATIVE_TIMEOUT | B_CAN_INTERRUPT); mutex_lock(&fLock); + + uint64 clientId = fClientId; + if (fCIDUseCount == 0) { fThreadCancel = true; mutex_unlock(&fLock); @@ -165,8 +275,10 @@ NFS4Server::_Renewal() Request request(fServer); request.Builder().Renew(fClientId); request.Send(); - mutex_unlock(&fLock); + + if (request.Reply().NFS4Error() == NFS4ERR_STALE_CLIENTID) + ServerRebooted(clientId); } return B_OK; diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h index 506b62e5d4..1bdc5a9f66 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h @@ -14,11 +14,17 @@ #include "RPCServer.h" +class OpenFileCookie; + class NFS4Server : public RPC::ProgramData { public: NFS4Server(RPC::Server* serv); virtual ~NFS4Server(); + uint64 ServerRebooted(uint64 clientId); + void AddOpenFile(OpenFileCookie* cookie); + void RemoveOpenFile(OpenFileCookie* cookie); + uint64 ClientId(uint64 prevId = 0, bool forceNew = false); void ReleaseCID(uint64 cid); @@ -26,6 +32,8 @@ public: inline uint32 LeaseTime(); private: + status_t _ReclaimOpen(OpenFileCookie* cookie); + status_t _GetLeaseTime(); status_t _StartRenewing(); @@ -42,6 +50,9 @@ private: vint32 fSequenceId; + OpenFileCookie* fOpenFiles; + mutex fOpenLock; + RPC::Server* fServer; }; diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp index d361b861d6..5a97137b0e 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp @@ -152,8 +152,8 @@ RequestBuilder::LookUpUp() status_t -RequestBuilder::Open(uint32 seq, uint32 access, uint64 id, OpenCreate oc, - const char* name) +RequestBuilder::Open(OpenClaim claim, uint32 seq, uint32 access, uint64 id, + OpenCreate oc, uint32 ownerTime, uint32 ownerTID, const char* name) { if (fProcedure != ProcCompound) return B_BAD_VALUE; @@ -168,17 +168,26 @@ RequestBuilder::Open(uint32 seq, uint32 access, uint64 id, OpenCreate oc, char owner[128]; int pos = 0; - *(uint32*)(owner + pos) = time(NULL); + *(uint32*)(owner + pos) = ownerTime; pos += sizeof(uint32); - *(uint32*)(owner + pos) = find_thread(NULL); + *(uint32*)(owner + pos) = ownerTID; pos += sizeof(uint32); fRequest->Stream().AddOpaque(owner, pos); fRequest->Stream().AddUInt(oc); - fRequest->Stream().AddUInt(0); // claim null - fRequest->Stream().AddString(name, strlen(name)); + fRequest->Stream().AddUInt(claim); + switch (claim) { + case CLAIM_NULL: + fRequest->Stream().AddString(name, strlen(name)); + break; + case CLAIM_PREVIOUS: + fRequest->Stream().AddUInt(0); + break; + default: + return B_UNSUPPORTED; + } fOpCount++; diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h index 21e2ecbf77..c13ea4365e 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h @@ -31,8 +31,10 @@ public: status_t GetFH(); status_t LookUp(const char* name); status_t LookUpUp(); - status_t Open(uint32 seq, uint32 access, uint64 id, - OpenCreate oc, const char* name); + status_t Open(OpenClaim claim, uint32 seq, + uint32 access, uint64 id, OpenCreate oc, + uint32 ownerTime, uint32 ownerTID, + const char* name); status_t OpenConfirm(uint32 seq, const uint32* id, uint32 stateSeq); status_t PutFH(const Filehandle& fh); From c702f887ad5ef4665e3d45d2e2edda325a9d6290 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Sat, 16 Jun 2012 17:40:36 +0200 Subject: [PATCH 054/252] nfs4: Add support for volatile filehandles --- .../kernel/file_systems/nfs4/Filehandle.h | 14 +- .../kernel/file_systems/nfs4/Filesystem.cpp | 27 +- .../kernel/file_systems/nfs4/Filesystem.h | 4 +- .../kernel/file_systems/nfs4/Inode.cpp | 698 +++++++++++------- src/add-ons/kernel/file_systems/nfs4/Inode.h | 4 + .../kernel/file_systems/nfs4/InodeIdMap.h | 12 +- 6 files changed, 443 insertions(+), 316 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Filehandle.h b/src/add-ons/kernel/file_systems/nfs4/Filehandle.h index 1aee36ce29..3fae5ef2d1 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Filehandle.h +++ b/src/add-ons/kernel/file_systems/nfs4/Filehandle.h @@ -36,8 +36,7 @@ struct FileInfo { Filehandle fParent; const char* fName; - - // ... full path may be needed if filehandles are volatile + const char* fPath; inline FileInfo(); inline ~FileInfo(); @@ -76,7 +75,8 @@ inline FileInfo::FileInfo() : fFileId(0), - fName(NULL) + fName(NULL), + fPath(NULL) { } @@ -85,6 +85,7 @@ inline FileInfo::~FileInfo() { free(const_cast(fName)); + free(const_cast(fPath)); } @@ -94,7 +95,8 @@ FileInfo::FileInfo(const FileInfo& fi) fFileId(fi.fFileId), fFH(fi.fFH), fParent(fi.fParent), - fName(strdup(fi.fName)) + fName(strdup(fi.fName)), + fPath(strdup(fi.fPath)) { } @@ -108,6 +110,10 @@ FileInfo::operator=(const FileInfo& fi) free(const_cast(fName)); fName = strdup(fi.fName); + + free(const_cast(fPath)); + fPath = strdup(fi.fPath); + return *this; } diff --git a/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp b/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp index 1ac6ddcb15..be5524171b 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp @@ -18,6 +18,7 @@ Filesystem::Filesystem() : + fPath(NULL), fId(1) { } @@ -25,6 +26,7 @@ Filesystem::Filesystem() Filesystem::~Filesystem() { + free(const_cast(fPath)); } @@ -60,8 +62,6 @@ Filesystem::Mount(Filesystem** pfs, RPC::Server* serv, const char* fsPath, req.GetFH(); req.Access(); - Attribute attr[] = { FATTR4_FH_EXPIRE_TYPE }; - req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); status_t result = request.Send(); if (result != B_OK) @@ -92,32 +92,12 @@ Filesystem::Mount(Filesystem** pfs, RPC::Server* serv, const char* fsPath, != (ACCESS4_READ | ACCESS4_LOOKUP)) return B_PERMISSION_DENIED; - AttrValue* values; - uint32 count; - result = reply.GetAttr(&values, &count); - if (result != B_OK) - return result; - - if (count != 1 || values[0].fAttribute != FATTR4_FH_EXPIRE_TYPE) { - delete[] values; - return B_BAD_VALUE; - } - - // Currently, only persistent filehandles are supported. That will be - // changed soon. - if (values[0].fData.fValue32 != FH4_PERSISTENT) { - delete[] values; - return B_UNSUPPORTED; - } - Filesystem* fs = new(std::nothrow) Filesystem; - fs->fFHExpiryType = values[0].fData.fValue32; + fs->fPath = strdup(fsPath); memcpy(&fs->fRootFH, &fh, sizeof(Filehandle)); fs->fServer = serv; fs->fDevId = id; - delete[] values; - *pfs = fs; return B_OK; @@ -152,6 +132,7 @@ Filesystem::CreateRootInode() fi.fFH = fRootFH; fi.fParent = fRootFH; fi.fName = strdup("/"); + fi.fPath = strdup(fPath); Inode* inode; status_t result = Inode::CreateInode(this, fi, &inode); diff --git a/src/add-ons/kernel/file_systems/nfs4/Filesystem.h b/src/add-ons/kernel/file_systems/nfs4/Filesystem.h index 380cbe42ec..2d1d076a94 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Filesystem.h +++ b/src/add-ons/kernel/file_systems/nfs4/Filesystem.h @@ -26,8 +26,6 @@ public: status_t GetInode(ino_t id, Inode** inode); Inode* CreateRootInode(); - inline uint32 FHExpiryType() const; - inline RPC::Server* Server(); inline NFS4Server* NFSServer(); @@ -38,7 +36,7 @@ public: private: Filesystem(); - uint32 fFHExpiryType; + const char* fPath; Filehandle fRootFH; diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index d1bc6a85e1..3fcaab1543 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -20,8 +20,6 @@ Inode::Inode() } -// Creating Inode object from Filehandle probably is not a good idea when -// filehandles are volatile. status_t Inode::CreateInode(Filesystem* fs, const FileInfo &fi, Inode** _inode) { @@ -33,47 +31,56 @@ Inode::CreateInode(Filesystem* fs, const FileInfo &fi, Inode** _inode) inode->fFilesystem = fs; inode->fParentFH = fi.fParent; inode->fName = strdup(fi.fName); + inode->fPath = strdup(fi.fPath); - Request request(fs->Server()); - RequestBuilder& req = request.Builder(); + do { + Request request(fs->Server()); + RequestBuilder& req = request.Builder(); - req.PutFH(inode->fHandle); + req.PutFH(inode->fHandle); - Attribute attr[] = { FATTR4_TYPE, FATTR4_FILEID }; - req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); + Attribute attr[] = { FATTR4_TYPE, FATTR4_FILEID }; + req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); - status_t result = request.Send(); - if (result != B_OK) - return result; + status_t result = request.Send(); + if (result != B_OK) + return result; - ReplyInterpreter& reply = request.Reply(); + ReplyInterpreter& reply = request.Reply(); - result = reply.PutFH(); - if (result != B_OK) - return result; + // filehandle has expired + if (reply.NFS4Error() == NFS4ERR_FHEXPIRED) { + inode->_LookUpFilehandle(); + continue; + } - AttrValue* values; - uint32 count; - result = reply.GetAttr(&values, &count); - if (result != B_OK || count < 1) - return result; + result = reply.PutFH(); + if (result != B_OK) + return result; - if (fi.fFileId == 0) { - if (count < 2 || values[1].fAttribute != FATTR4_FILEID) - inode->fFileId = fs->AllocFileId(); - else - inode->fFileId = values[1].fData.fValue64; - } else - inode->fFileId = fi.fFileId; + AttrValue* values; + uint32 count; + result = reply.GetAttr(&values, &count); + if (result != B_OK || count < 1) + return result; - // FATTR4_TYPE is mandatory - inode->fType = values[0].fData.fValue32; + if (fi.fFileId == 0) { + if (count < 2 || values[1].fAttribute != FATTR4_FILEID) + inode->fFileId = fs->AllocFileId(); + else + inode->fFileId = values[1].fData.fValue64; + } else + inode->fFileId = fi.fFileId; - delete[] values; + // FATTR4_TYPE is mandatory + inode->fType = values[0].fData.fValue32; - *_inode = inode; + delete[] values; - return B_OK; + *_inode = inode; + + return B_OK; + } while (true); } @@ -94,60 +101,82 @@ Inode::LookUp(const char* name, ino_t* id) return B_OK; } - Request request(fFilesystem->Server()); - RequestBuilder& req = request.Builder(); + do { + Request request(fFilesystem->Server()); + RequestBuilder& req = request.Builder(); - req.PutFH(fHandle); + req.PutFH(fHandle); - if (!strcmp(name, "..")) - req.LookUpUp(); - else - req.LookUp(name); + if (!strcmp(name, "..")) + req.LookUpUp(); + else + req.LookUp(name); - req.GetFH(); + req.GetFH(); - Attribute attr[] = { FATTR4_FILEID }; - req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); + Attribute attr[] = { FATTR4_FILEID }; + req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); - status_t result = request.Send(); - if (result != B_OK) - return result; + status_t result = request.Send(); + if (result != B_OK) + return result; - ReplyInterpreter& reply = request.Reply(); + ReplyInterpreter& reply = request.Reply(); - result = reply.PutFH(); - if (result != B_OK) - return result; + // filehandle has expired + if (reply.NFS4Error() == NFS4ERR_FHEXPIRED) { + _LookUpFilehandle(); + continue; + } - if (!strcmp(name, "..")) - result = reply.LookUpUp(); - else - result = reply.LookUp(); - if (result != B_OK) - return result; + result = reply.PutFH(); + if (result != B_OK) + return result; - Filehandle fh; - result = reply.GetFH(&fh); - if (result != B_OK) - return result; + if (!strcmp(name, "..")) + result = reply.LookUpUp(); + else + result = reply.LookUp(); + if (result != B_OK) + return result; - AttrValue* values; - uint32 count; - result = reply.GetAttr(&values, &count); - if (result != B_OK) - return result; + Filehandle fh; + result = reply.GetFH(&fh); + if (result != B_OK) + return result; - uint64 fileId; - if (count < 1 || values[0].fAttribute != FATTR4_FILEID) - fileId = fFilesystem->AllocFileId(); - else - fileId = values[0].fData.fValue64; - delete[] values; + AttrValue* values; + uint32 count; + result = reply.GetAttr(&values, &count); + if (result != B_OK) + return result; - *id = _FileIdToInoT(fileId); - fFilesystem->InoIdMap()->AddEntry(fh, fHandle, name, fileId, *id); + uint64 fileId; + if (count < 1 || values[0].fAttribute != FATTR4_FILEID) + fileId = fFilesystem->AllocFileId(); + else + fileId = values[0].fData.fValue64; + delete[] values; - return B_OK; + *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); + + return B_OK; + } while (true); } @@ -157,179 +186,204 @@ Inode::ReadLink(void* buffer, size_t* length) if (fType != NF4LNK) return B_BAD_VALUE; - Request request(fFilesystem->Server()); - RequestBuilder& req = request.Builder(); + do { + Request request(fFilesystem->Server()); + RequestBuilder& req = request.Builder(); - req.PutFH(fHandle); - req.ReadLink(); + req.PutFH(fHandle); + req.ReadLink(); + + status_t result = request.Send(); + if (result != B_OK) + return result; + + ReplyInterpreter& reply = request.Reply(); + + // filehandle has expired + if (reply.NFS4Error() == NFS4ERR_FHEXPIRED) { + _LookUpFilehandle(); + continue; + } + + result = reply.PutFH(); + if (result != B_OK) + return result; + + uint32 size; + result = reply.ReadLink(buffer, &size, *length); + *length = static_cast(size); - status_t result = request.Send(); - if (result != B_OK) return result; - - ReplyInterpreter& reply = request.Reply(); - - result = reply.PutFH(); - if (result != B_OK) - return result; - - uint32 size; - result = reply.ReadLink(buffer, &size, *length); - *length = static_cast(size); - - return result; + } while (true); } status_t Inode::Access(int mode) { - Request request(fFilesystem->Server()); - RequestBuilder& req = request.Builder(); + do { + Request request(fFilesystem->Server()); + RequestBuilder& req = request.Builder(); - req.PutFH(fHandle); - req.Access(); + req.PutFH(fHandle); + req.Access(); - status_t result = request.Send(); - if (result != B_OK) - return result; + status_t result = request.Send(); + if (result != B_OK) + return result; - ReplyInterpreter& reply = request.Reply(); + ReplyInterpreter& reply = request.Reply(); - result = reply.PutFH(); - if (result != B_OK) - return result; + // filehandle has expired + if (reply.NFS4Error() == NFS4ERR_FHEXPIRED) { + _LookUpFilehandle(); + continue; + } - uint32 allowed; - result = reply.Access(NULL, &allowed); - if (result != B_OK) - return result; + result = reply.PutFH(); + if (result != B_OK) + return result; - int acc = 0; - if ((allowed & ACCESS4_READ) != 0) - acc |= R_OK; + uint32 allowed; + result = reply.Access(NULL, &allowed); + if (result != B_OK) + return result; - if (fType == NF4DIR && (allowed & ACCESS4_LOOKUP) != 0) - acc |= X_OK | R_OK; + int acc = 0; + if ((allowed & ACCESS4_READ) != 0) + acc |= R_OK; - if (fType != NF4DIR && (allowed & ACCESS4_EXECUTE) != 0) - acc |= X_OK; + if (fType == NF4DIR && (allowed & ACCESS4_LOOKUP) != 0) + acc |= X_OK | R_OK; - if ((allowed & ACCESS4_MODIFY) != 0) - acc |= W_OK; + if (fType != NF4DIR && (allowed & ACCESS4_EXECUTE) != 0) + acc |= X_OK; - if ((mode & acc) != mode) - return B_NOT_ALLOWED; + if ((allowed & ACCESS4_MODIFY) != 0) + acc |= W_OK; - return B_OK; + if ((mode & acc) != mode) + return B_NOT_ALLOWED; + + return B_OK; + } while (true); } status_t Inode::Stat(struct stat* st) { - Request request(fFilesystem->Server()); - RequestBuilder& req = request.Builder(); + do { + Request request(fFilesystem->Server()); + RequestBuilder& req = request.Builder(); - req.PutFH(fHandle); + req.PutFH(fHandle); - Attribute attr[] = { FATTR4_SIZE, FATTR4_MODE, FATTR4_NUMLINKS, - FATTR4_TIME_ACCESS, FATTR4_TIME_CREATE, - FATTR4_TIME_METADATA, FATTR4_TIME_MODIFY }; - req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); + Attribute attr[] = { FATTR4_SIZE, FATTR4_MODE, FATTR4_NUMLINKS, + FATTR4_TIME_ACCESS, FATTR4_TIME_CREATE, + FATTR4_TIME_METADATA, FATTR4_TIME_MODIFY }; + req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); - status_t result = request.Send(); - if (result != B_OK) - return result; + status_t result = request.Send(); + if (result != B_OK) + return result; - ReplyInterpreter& reply = request.Reply(); + ReplyInterpreter& reply = request.Reply(); - result = reply.PutFH(); - if (result != B_OK) - return result; + // filehandle has expired + if (reply.NFS4Error() == NFS4ERR_FHEXPIRED) { + _LookUpFilehandle(); + continue; + } - AttrValue* values; - uint32 count; - result = reply.GetAttr(&values, &count); - if (result != B_OK) - return result; + result = reply.PutFH(); + if (result != B_OK) + return result; + + AttrValue* values; + uint32 count; + result = reply.GetAttr(&values, &count); + if (result != B_OK) + return result; + + // FATTR4_SIZE is mandatory + if (count < 1 || values[0].fAttribute != FATTR4_SIZE) { + delete[] values; + return B_BAD_VALUE; + } + st->st_size = values[0].fData.fValue64; + + uint32 next = 1; + st->st_mode = Type(); + if (count >= next && values[next].fAttribute == FATTR4_MODE) { + st->st_mode |= values[next].fData.fValue32; + next++; + } else { + // Try to guess using ACCESS request + request.Reset(); + request.Builder().PutFH(fHandle); + request.Builder().Access(); + result = request.Send(); + if (result != B_OK) + return result; + result = request.Reply().PutFH(); + if (result != B_OK) + return result; + uint32 prvl; + result = request.Reply().Access(NULL, &prvl); + if (result != B_OK) + return result; + + if ((prvl & ACCESS4_READ) != 0) + st->st_mode |= S_IRUSR | S_IRGRP | S_IROTH; + + if ((prvl & ACCESS4_MODIFY) != 0) + st->st_mode |= S_IWUSR | S_IWGRP | S_IWOTH; + + if (fType == NF4DIR && (prvl & ACCESS4_LOOKUP) != 0) + st->st_mode |= S_IXUSR | S_IXGRP | S_IXOTH; + + if (fType != NF4DIR && (prvl & ACCESS4_EXECUTE) != 0) + st->st_mode |= S_IXUSR | S_IXGRP | S_IXOTH; + } + + if (count >= next && values[next].fAttribute == FATTR4_NUMLINKS) { + st->st_nlink = values[next].fData.fValue32; + next++; + } else + st->st_nlink = 1; + + if (count >= next && values[next].fAttribute == FATTR4_TIME_ACCESS) { + memcpy(&st->st_atim, values[next].fData.fPointer, sizeof(timespec)); + next++; + } else + memset(&st->st_atim, 0, sizeof(timespec)); + + if (count >= next && values[next].fAttribute == FATTR4_TIME_CREATE) { + memcpy(&st->st_crtim, values[next].fData.fPointer, + sizeof(timespec)); + next++; + } else + memset(&st->st_crtim, 0, sizeof(timespec)); + + if (count >= next && values[next].fAttribute == FATTR4_TIME_METADATA) { + memcpy(&st->st_ctim, values[next].fData.fPointer, sizeof(timespec)); + next++; + } else + memset(&st->st_ctim, 0, sizeof(timespec)); + + if (count >= next && values[next].fAttribute == FATTR4_TIME_MODIFY) { + memcpy(&st->st_mtim, values[next].fData.fPointer, sizeof(timespec)); + next++; + } else + memset(&st->st_mtim, 0, sizeof(timespec)); + + st->st_uid = 0; + st->st_gid = 0; - // FATTR4_SIZE is mandatory - if (count < 1 || values[0].fAttribute != FATTR4_SIZE) { delete[] values; - return B_BAD_VALUE; - } - st->st_size = values[0].fData.fValue64; - - uint32 next = 1; - st->st_mode = Type(); - if (count >= next && values[next].fAttribute == FATTR4_MODE) { - st->st_mode |= values[next].fData.fValue32; - next++; - } else { - // Try to guess using ACCESS request - request.Reset(); - request.Builder().PutFH(fHandle); - request.Builder().Access(); - result = request.Send(); - if (result != B_OK) - return result; - result = request.Reply().PutFH(); - if (result != B_OK) - return result; - uint32 prvl; - result = request.Reply().Access(NULL, &prvl); - if (result != B_OK) - return result; - - if ((prvl & ACCESS4_READ) != 0) - st->st_mode |= S_IRUSR | S_IRGRP | S_IROTH; - - if ((prvl & ACCESS4_MODIFY) != 0) - st->st_mode |= S_IWUSR | S_IWGRP | S_IWOTH; - - if (fType == NF4DIR && (prvl & ACCESS4_LOOKUP) != 0) - st->st_mode |= S_IXUSR | S_IXGRP | S_IXOTH; - - if (fType != NF4DIR && (prvl & ACCESS4_EXECUTE) != 0) - st->st_mode |= S_IXUSR | S_IXGRP | S_IXOTH; - } - - if (count >= next && values[next].fAttribute == FATTR4_NUMLINKS) { - st->st_nlink = values[next].fData.fValue32; - next++; - } else - st->st_nlink = 1; - - if (count >= next && values[next].fAttribute == FATTR4_TIME_ACCESS) { - memcpy(&st->st_atim, values[next].fData.fPointer, sizeof(timespec)); - next++; - } else - memset(&st->st_atim, 0, sizeof(timespec)); - - if (count >= next && values[next].fAttribute == FATTR4_TIME_CREATE) { - memcpy(&st->st_crtim, values[next].fData.fPointer, sizeof(timespec)); - next++; - } else - memset(&st->st_crtim, 0, sizeof(timespec)); - - if (count >= next && values[next].fAttribute == FATTR4_TIME_METADATA) { - memcpy(&st->st_ctim, values[next].fData.fPointer, sizeof(timespec)); - next++; - } else - memset(&st->st_ctim, 0, sizeof(timespec)); - - if (count >= next && values[next].fAttribute == FATTR4_TIME_MODIFY) { - memcpy(&st->st_mtim, values[next].fData.fPointer, sizeof(timespec)); - next++; - } else - memset(&st->st_mtim, 0, sizeof(timespec)); - - st->st_uid = 0; - st->st_gid = 0; - - delete[] values; - return B_OK; + return B_OK; + } while (true); } @@ -362,6 +416,12 @@ Inode::Open(int mode, OpenFileCookie* cookie) ReplyInterpreter& reply = request.Reply(); + // filehandle has expired + if (reply.NFS4Error() == NFS4ERR_FHEXPIRED) { + _LookUpFilehandle(); + continue; + } + // server is in grace period, we need to wait if (reply.NFS4Error() == NFS4ERR_GRACE) { fFilesystem->NFSServer()->ReleaseCID(cookie->fClientId); @@ -437,6 +497,12 @@ Inode::Close(OpenFileCookie* cookie) ReplyInterpreter& reply = request.Reply(); + // filehandle has expired + if (reply.NFS4Error() == NFS4ERR_FHEXPIRED) { + _LookUpFilehandle(); + continue; + } + // server is in grace period, we need to wait if (reply.NFS4Error() == NFS4ERR_GRACE) { snooze_etc(fFilesystem->NFSServer()->LeaseTime() / 3, @@ -483,6 +549,12 @@ Inode::Read(OpenFileCookie* cookie, off_t pos, void* buffer, size_t* _length) ReplyInterpreter& reply = request.Reply(); + // filehandle has expired + if (reply.NFS4Error() == NFS4ERR_FHEXPIRED) { + _LookUpFilehandle(); + continue; + } + // server is in grace period, we need to wait if (reply.NFS4Error() == NFS4ERR_GRACE) { snooze_etc(fFilesystem->NFSServer()->LeaseTime() / 3, @@ -524,34 +596,42 @@ Inode::OpenDir(uint64* cookie) if (fType != NF4DIR) return B_NOT_A_DIRECTORY; - Request request(fFilesystem->Server()); - RequestBuilder& req = request.Builder(); + do { + Request request(fFilesystem->Server()); + RequestBuilder& req = request.Builder(); - req.PutFH(fHandle); - req.Access(); + req.PutFH(fHandle); + req.Access(); - status_t result = request.Send(); - if (result != B_OK) - return result; + status_t result = request.Send(); + if (result != B_OK) + return result; - ReplyInterpreter& reply = request.Reply(); + ReplyInterpreter& reply = request.Reply(); - result = reply.PutFH(); - if (result != B_OK) - return result; + // filehandle has expired + if (reply.NFS4Error() == NFS4ERR_FHEXPIRED) { + _LookUpFilehandle(); + continue; + } - uint32 allowed; - result = reply.Access(NULL, &allowed); - if (result != B_OK) - return result; + result = reply.PutFH(); + if (result != B_OK) + return result; - if (allowed & ACCESS4_READ != ACCESS4_READ) - return B_PERMISSION_DENIED; + uint32 allowed; + result = reply.Access(NULL, &allowed); + if (result != B_OK) + return result; - cookie[0] = 0; - cookie[1] = 2; + if (allowed & ACCESS4_READ != ACCESS4_READ) + return B_PERMISSION_DENIED; - return B_OK; + cookie[0] = 0; + cookie[1] = 2; + + return B_OK; + } while (true); } @@ -559,25 +639,33 @@ status_t Inode::_ReadDirOnce(DirEntry** dirents, uint32* count, uint64* cookie, bool* eof) { - Request request(fFilesystem->Server()); - RequestBuilder& req = request.Builder(); + do { + Request request(fFilesystem->Server()); + RequestBuilder& req = request.Builder(); - req.PutFH(fHandle); + req.PutFH(fHandle); - Attribute attr[] = { FATTR4_FILEID }; - req.ReadDir(*count, cookie, attr, sizeof(attr) / sizeof(Attribute)); + Attribute attr[] = { FATTR4_FILEID }; + req.ReadDir(*count, cookie, attr, sizeof(attr) / sizeof(Attribute)); - status_t result = request.Send(); - if (result != B_OK) - return result; + status_t result = request.Send(); + if (result != B_OK) + return result; - ReplyInterpreter& reply = request.Reply(); + ReplyInterpreter& reply = request.Reply(); - result = reply.PutFH(); - if (result != B_OK) - return result; + // filehandle has expired + if (reply.NFS4Error() == NFS4ERR_FHEXPIRED) { + _LookUpFilehandle(); + continue; + } - return reply.ReadDir(cookie, dirents, count, eof); + result = reply.PutFH(); + if (result != B_OK) + return result; + + return reply.ReadDir(cookie, dirents, count, eof); + } while (true); } @@ -606,47 +694,55 @@ Inode::_FillDirEntry(struct dirent* de, ino_t id, const char* name, uint32 pos, status_t Inode::_ReadDirUp(struct dirent* de, uint32 pos, uint32 size) { - Request request(fFilesystem->Server()); - RequestBuilder& req = request.Builder(); + do { + Request request(fFilesystem->Server()); + RequestBuilder& req = request.Builder(); - req.PutFH(fHandle); - req.LookUpUp(); - req.GetFH(); - Attribute attr[] = { FATTR4_FILEID }; - req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); + req.PutFH(fHandle); + req.LookUpUp(); + req.GetFH(); + Attribute attr[] = { FATTR4_FILEID }; + req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); - status_t result = request.Send(); - if (result != B_OK) - return result; + status_t result = request.Send(); + if (result != B_OK) + return result; - ReplyInterpreter& reply = request.Reply(); + ReplyInterpreter& reply = request.Reply(); - result = reply.PutFH(); - if (result != B_OK) - return result; + // filehandle has expired + if (reply.NFS4Error() == NFS4ERR_FHEXPIRED) { + _LookUpFilehandle(); + continue; + } - result = reply.LookUpUp(); - if (result != B_OK) - return result; + result = reply.PutFH(); + if (result != B_OK) + return result; - Filehandle fh; - result = reply.GetFH(&fh); - if (result != B_OK) - return result; + result = reply.LookUpUp(); + if (result != B_OK) + return result; - AttrValue* values; - uint32 count; - result = reply.GetAttr(&values, &count); - if (result != B_OK) - return result; + Filehandle fh; + result = reply.GetFH(&fh); + if (result != B_OK) + return result; - uint64 fileId; - if (count < 1 || values[0].fAttribute != FATTR4_FILEID) { - fileId = fFilesystem->AllocFileId(); - } else - fileId = values[0].fData.fValue64; + AttrValue* values; + uint32 count; + result = reply.GetAttr(&values, &count); + if (result != B_OK) + return result; - return _FillDirEntry(de, _FileIdToInoT(fileId), "..", pos, size); + uint64 fileId; + if (count < 1 || values[0].fAttribute != FATTR4_FILEID) { + fileId = fFilesystem->AllocFileId(); + } else + fileId = values[0].fData.fValue64; + + return _FillDirEntry(de, _FileIdToInoT(fileId), "..", pos, size); + } while (true); } // TODO: Currently inode numbers returned by ReadDir are virtually random. @@ -726,3 +822,53 @@ Inode::ReadDir(void* _buffer, uint32 size, uint32* _count, uint64* cookie) return B_OK; } + +status_t +Inode::_LookUpFilehandle() +{ + Request request(fFilesystem->Server()); + RequestBuilder& req = request.Builder(); + + req.PutRootFH(); + + uint32 lookupCount = 0; + char* path = strdup(fPath); + char* pathStart = path; + char* pathEnd; + while (pathStart != NULL) { + pathEnd = strpbrk(pathStart, "/"); + if (pathEnd != NULL) + *pathEnd = '\0'; + + req.LookUp(pathStart); + + if (pathEnd != NULL && pathEnd[1] != '\0') + pathStart = pathEnd + 1; + else + pathStart = NULL; + + lookupCount++; + } + free(path); + + req.GetFH(); + + status_t result = request.Send(); + if (result != B_OK) + return result; + + ReplyInterpreter& reply = request.Reply(); + + result = reply.PutRootFH(); + if (result != B_OK) + return result; + + for (uint32 i = 0; i < lookupCount; i++) { + result = reply.LookUp(); + if (result != B_OK) + return result; + } + + return reply.GetFH(&fHandle); +} + diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h b/src/add-ons/kernel/file_systems/nfs4/Inode.h index edbfbece07..d8c7520dda 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -61,6 +61,8 @@ public: private: Inode(); + status_t _LookUpFilehandle(); + status_t _ReadDirOnce(DirEntry** dirents, uint32* count, uint64* cookie, bool* eof); status_t _FillDirEntry(struct dirent* de, ino_t id, @@ -78,6 +80,8 @@ private: Filehandle fParentFH; const char* fName; + + const char* fPath; }; diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeIdMap.h b/src/add-ons/kernel/file_systems/nfs4/InodeIdMap.h index bf73f0a9d1..88692037d7 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeIdMap.h +++ b/src/add-ons/kernel/file_systems/nfs4/InodeIdMap.h @@ -17,9 +17,7 @@ class InodeIdMap { public: - inline status_t AddEntry(const Filehandle& fh, - const Filehandle& parent, - const char* name, uint64 fileId, + inline status_t AddEntry(const FileInfo& fi, ino_t id); inline status_t GetFileInfo(FileInfo* fi, ino_t id); @@ -30,14 +28,8 @@ private: inline status_t -InodeIdMap::AddEntry(const Filehandle& fh, const Filehandle& parent, - const char* name, uint64 fileId, ino_t id) +InodeIdMap::AddEntry(const FileInfo& fi, ino_t id) { - FileInfo fi; - fi.fFileId = fileId; - fi.fFH = fh; - fi.fParent = parent; - fi.fName = strdup(name); return fMap.Insert(id, fi); } From 941416ff8b37ee51eb663cb75c4d94e5d668766a Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Sat, 16 Jun 2012 18:21:16 +0200 Subject: [PATCH 055/252] nfs4: Add read_fs_info hook --- .../kernel/file_systems/nfs4/Filesystem.cpp | 74 +++++++++++++++++++ .../kernel/file_systems/nfs4/Filesystem.h | 4 + .../file_systems/nfs4/ReplyInterpreter.cpp | 36 +++++++++ .../file_systems/nfs4/kernel_interface.cpp | 10 ++- 4 files changed, 123 insertions(+), 1 deletion(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp b/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp index be5524171b..2913418884 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp @@ -142,3 +142,77 @@ Filesystem::CreateRootInode() return NULL; } + +status_t +Filesystem::ReadInfo(struct fs_info* info) +{ + Request request(fServer); + RequestBuilder& req = request.Builder(); + + req.PutFH(fRootFH); + Attribute attr[] = { FATTR4_FILES_FREE, FATTR4_FILES_TOTAL, + FATTR4_MAXREAD, FATTR4_MAXWRITE, FATTR4_SPACE_FREE, + FATTR4_SPACE_TOTAL }; + req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); + + status_t result = request.Send(); + if (result != B_OK) + return result; + + ReplyInterpreter& reply = request.Reply(); + + result = reply.PutFH(); + if (result != B_OK) + return result; + + AttrValue* values; + uint32 count, next = 0; + result = reply.GetAttr(&values, &count); + if (result != B_OK) + return result; + + if (count >= next && values[next].fAttribute == FATTR4_FILES_FREE) { + info->free_nodes = values[next].fData.fValue64; + next++; + } + + if (count >= next && values[next].fAttribute == FATTR4_FILES_TOTAL) { + info->total_nodes = values[next].fData.fValue64; + next++; + } + + uint64 io_size = LONGLONG_MAX; + if (count >= next && values[next].fAttribute == FATTR4_MAXREAD) { + io_size = min_c(io_size, values[next].fData.fValue64); + next++; + } + + if (count >= next && values[next].fAttribute == FATTR4_MAXWRITE) { + io_size = min_c(io_size, values[next].fData.fValue64); + next++; + } + + if (io_size == LONGLONG_MAX) + io_size = 32768; + info->io_size = io_size; + info->block_size = io_size; + + if (count >= next && values[next].fAttribute == FATTR4_SPACE_FREE) { + info->free_blocks = values[next].fData.fValue64 / io_size; + next++; + } + + if (count >= next && values[next].fAttribute == FATTR4_SPACE_TOTAL) { + info->total_blocks = values[next].fData.fValue64 / io_size; + next++; + } + + info->flags = B_FS_IS_READONLY; + const char* name = strrchr(fPath, '/'); + if (name != NULL) + name++; + strncpy(info->volume_name, name, B_FILE_NAME_LENGTH); + + return B_OK; +} + diff --git a/src/add-ons/kernel/file_systems/nfs4/Filesystem.h b/src/add-ons/kernel/file_systems/nfs4/Filesystem.h index 2d1d076a94..7000f4bd59 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Filesystem.h +++ b/src/add-ons/kernel/file_systems/nfs4/Filesystem.h @@ -9,6 +9,8 @@ #define FILESYSTEM_H +#include + #include "InodeIdMap.h" #include "NFS4Defs.h" #include "NFS4Server.h" @@ -26,6 +28,8 @@ public: status_t GetInode(ino_t id, Inode** inode); Inode* CreateRootInode(); + status_t ReadInfo(struct fs_info* info); + inline RPC::Server* Server(); inline NFS4Server* NFSServer(); diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp index 756e7239a5..cd9378f523 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp @@ -349,6 +349,30 @@ ReplyInterpreter::_DecodeAttrs(XDR::ReadStream& str, AttrValue** attrs, current++; } + if (sIsAttrSet(FATTR4_FILES_FREE, bitmap, bcount)) { + values[current].fAttribute = FATTR4_FILES_FREE; + values[current].fData.fValue64 = stream.GetUHyper(); + current++; + } + + if (sIsAttrSet(FATTR4_FILES_TOTAL, bitmap, bcount)) { + values[current].fAttribute = FATTR4_FILES_TOTAL; + values[current].fData.fValue64 = stream.GetUHyper(); + current++; + } + + if (sIsAttrSet(FATTR4_MAXREAD, bitmap, bcount)) { + values[current].fAttribute = FATTR4_MAXREAD; + values[current].fData.fValue64 = stream.GetUHyper(); + current++; + } + + if (sIsAttrSet(FATTR4_MAXWRITE, bitmap, bcount)) { + values[current].fAttribute = FATTR4_MAXWRITE; + values[current].fData.fValue64 = stream.GetUHyper(); + current++; + } + if (sIsAttrSet(FATTR4_MODE, bitmap, bcount)) { values[current].fAttribute = FATTR4_MODE; values[current].fData.fValue32 = stream.GetUInt(); @@ -361,6 +385,18 @@ ReplyInterpreter::_DecodeAttrs(XDR::ReadStream& str, AttrValue** attrs, current++; } + if (sIsAttrSet(FATTR4_SPACE_FREE, bitmap, bcount)) { + values[current].fAttribute = FATTR4_SPACE_FREE; + values[current].fData.fValue64 = stream.GetUHyper(); + current++; + } + + if (sIsAttrSet(FATTR4_SPACE_TOTAL, bitmap, bcount)) { + values[current].fAttribute = FATTR4_SPACE_TOTAL; + values[current].fData.fValue64 = stream.GetUHyper(); + current++; + } + if (sIsAttrSet(FATTR4_TIME_ACCESS, bitmap, bcount)) { values[current].fAttribute = FATTR4_TIME_ACCESS; values[current].fFreePointer = true; 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 bd44f8dffd..281fe9b371 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -112,6 +112,14 @@ nfs4_unmount(fs_volume* volume) } +static status_t +nfs4_read_fs_info(fs_volume* volume, struct fs_info* info) +{ + Filesystem* fs = reinterpret_cast(volume->private_volume); + return fs->ReadInfo(info); +} + + static status_t nfs4_lookup(fs_volume* volume, fs_vnode* dir, const char* name, ino_t* _id) { @@ -323,7 +331,7 @@ nfs4_std_ops(int32 op, ...) fs_volume_ops gNFSv4VolumeOps = { nfs4_unmount, - NULL, + nfs4_read_fs_info, NULL, NULL, nfs4_get_vnode, From 5a451a5405216830bb61289f75c14ce8f3bc992d Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Sat, 16 Jun 2012 21:58:13 +0200 Subject: [PATCH 056/252] nfs4: Fix OPEN and CLOSE sequence numbers --- .../kernel/file_systems/nfs4/Inode.cpp | 19 +++++++++--------- src/add-ons/kernel/file_systems/nfs4/Inode.h | 20 ++++++++++--------- .../kernel/file_systems/nfs4/NFS4Server.cpp | 11 +++++----- .../kernel/file_systems/nfs4/NFS4Server.h | 10 ---------- .../file_systems/nfs4/RequestBuilder.cpp | 9 +++------ .../kernel/file_systems/nfs4/RequestBuilder.h | 3 +-- 6 files changed, 30 insertions(+), 42 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index 3fcaab1543..1a50bb6834 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -15,6 +15,9 @@ #include "Request.h" +vint64 OpenFileCookie::fLastOwnerId = 0; + + Inode::Inode() { } @@ -395,6 +398,7 @@ Inode::Open(int mode, OpenFileCookie* cookie) cookie->fHandle = fHandle; cookie->fMode = mode; + cookie->fSequence = 0; do { cookie->fClientId = fFilesystem->NFSServer()->ClientId(); @@ -402,13 +406,11 @@ Inode::Open(int mode, OpenFileCookie* cookie) Request request(fFilesystem->Server()); RequestBuilder& req = request.Builder(); - cookie->fOwnerTime = time(NULL); - cookie->fOwnerTID = find_thread(NULL); + cookie->fOwnerId = atomic_add64(&cookie->fLastOwnerId, 1); req.PutFH(fParentFH); - req.Open(CLAIM_NULL, fFilesystem->NFSServer()->SequenceId(), - OPEN4_SHARE_ACCESS_READ, cookie->fClientId, OPEN4_NOCREATE, - cookie->fOwnerTime, cookie->fOwnerTID, fName); + req.Open(CLAIM_NULL, cookie->fSequence++, OPEN4_SHARE_ACCESS_READ, + cookie->fClientId, OPEN4_NOCREATE, cookie->fOwnerId, fName); result = request.Send(); if (result != B_OK) @@ -434,7 +436,6 @@ Inode::Open(int mode, OpenFileCookie* cookie) if (result != B_OK) return result; - result = reply.Open(cookie->fStateId, &cookie->fStateSeq, &confirm); if (result != B_OK) return result; @@ -450,8 +451,8 @@ Inode::Open(int mode, OpenFileCookie* cookie) RequestBuilder& req = request.Builder(); req.PutFH(fHandle); - req.OpenConfirm(fFilesystem->NFSServer()->SequenceId(), - cookie->fStateId, cookie->fStateSeq); + req.OpenConfirm(cookie->fSequence++, cookie->fStateId, + cookie->fStateSeq); result = request.Send(); if (result != B_OK) { @@ -488,7 +489,7 @@ Inode::Close(OpenFileCookie* cookie) RequestBuilder& req = request.Builder(); req.PutFH(fHandle); - req.Close(fFilesystem->NFSServer()->SequenceId(), cookie->fStateId, + req.Close(cookie->fSequence++, cookie->fStateId, cookie->fStateSeq); status_t result = request.Send(); diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h b/src/add-ons/kernel/file_systems/nfs4/Inode.h index d8c7520dda..d60873a98a 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -19,19 +19,21 @@ struct OpenFileCookie { - uint64 fClientId; + uint64 fClientId; - uint32 fMode; + uint32 fMode; - Filehandle fHandle; - uint32 fStateId[3]; - uint32 fStateSeq; + Filehandle fHandle; + uint32 fStateId[3]; + uint32 fStateSeq; - uint32 fOwnerTime; - uint32 fOwnerTID; + uint32 fSequence; - OpenFileCookie* fNext; - OpenFileCookie* fPrev; + uint64 fOwnerId; + static vint64 fLastOwnerId; + + OpenFileCookie* fNext; + OpenFileCookie* fPrev; }; class Inode { diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp index 3eab8ab502..2a0d7b1e49 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp @@ -17,7 +17,6 @@ NFS4Server::NFS4Server(RPC::Server* serv) fThreadCancel(true), fLeaseTime(0), fCIDUseCount(0), - fSequenceId(0), fOpenFiles(NULL), fServer(serv) { @@ -72,11 +71,10 @@ NFS4Server::_ReclaimOpen(OpenFileCookie* cookie) RequestBuilder& req = request.Builder(); req.PutFH(cookie->fHandle); - req.Open(CLAIM_PREVIOUS, SequenceId(), OPEN4_SHARE_ACCESS_READ, - cookie->fClientId, OPEN4_NOCREATE, cookie->fOwnerTime, - cookie->fOwnerTID, NULL); + req.Open(CLAIM_PREVIOUS, cookie->fSequence++, OPEN4_SHARE_ACCESS_READ, + cookie->fClientId, OPEN4_NOCREATE, cookie->fOwnerId, NULL); - status_t result = request.Send(); + status_t result = request.Send();; if (result != B_OK) return result; @@ -95,7 +93,8 @@ NFS4Server::_ReclaimOpen(OpenFileCookie* cookie) request.Reset(); req.PutFH(cookie->fHandle); - req.OpenConfirm(SequenceId(), cookie->fStateId, cookie->fStateSeq); + req.OpenConfirm(cookie->fSequence++, cookie->fStateId, + cookie->fStateSeq); result = request.Send(); if (result != B_OK) diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h index 1bdc5a9f66..ebe83d2ade 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h @@ -28,8 +28,6 @@ public: uint64 ClientId(uint64 prevId = 0, bool forceNew = false); void ReleaseCID(uint64 cid); - inline uint32 SequenceId(); - inline uint32 LeaseTime(); private: status_t _ReclaimOpen(OpenFileCookie* cookie); @@ -48,20 +46,12 @@ private: uint32 fCIDUseCount; mutex fLock; - vint32 fSequenceId; - OpenFileCookie* fOpenFiles; mutex fOpenLock; RPC::Server* fServer; }; -inline uint32 -NFS4Server::SequenceId() -{ - return static_cast(atomic_add(&fSequenceId, 1)); -} - inline uint32 NFS4Server::LeaseTime() diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp index 5a97137b0e..35bcb2c1fb 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp @@ -153,7 +153,7 @@ RequestBuilder::LookUpUp() status_t RequestBuilder::Open(OpenClaim claim, uint32 seq, uint32 access, uint64 id, - OpenCreate oc, uint32 ownerTime, uint32 ownerTID, const char* name) + OpenCreate oc, uint64 ownerId, const char* name) { if (fProcedure != ProcCompound) return B_BAD_VALUE; @@ -168,11 +168,8 @@ RequestBuilder::Open(OpenClaim claim, uint32 seq, uint32 access, uint64 id, char owner[128]; int pos = 0; - *(uint32*)(owner + pos) = ownerTime; - pos += sizeof(uint32); - - *(uint32*)(owner + pos) = ownerTID; - pos += sizeof(uint32); + *(uint64*)(owner + pos) = ownerId; + pos += sizeof(uint64); fRequest->Stream().AddOpaque(owner, pos); diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h index c13ea4365e..a557c65344 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h @@ -33,8 +33,7 @@ public: status_t LookUpUp(); status_t Open(OpenClaim claim, uint32 seq, uint32 access, uint64 id, OpenCreate oc, - uint32 ownerTime, uint32 ownerTID, - const char* name); + uint64 ownerId, const char* name); status_t OpenConfirm(uint32 seq, const uint32* id, uint32 stateSeq); status_t PutFH(const Filehandle& fh); From 5fb2be8872387f03c7f78e8734322f2b2588978c Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Sat, 16 Jun 2012 22:19:25 +0200 Subject: [PATCH 057/252] nfs4: Allow opening symbolic links --- src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) 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 281fe9b371..48fe7a956f 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -183,7 +183,7 @@ nfs4_open(fs_volume* volume, fs_vnode* vnode, int openMode, void** _cookie) { Inode* inode = reinterpret_cast(vnode->private_node); - if (inode->Type() == S_IFDIR) { + if (inode->Type() == S_IFDIR || inode->Type() == S_IFLNK) { *_cookie = NULL; return B_OK; } @@ -214,7 +214,7 @@ nfs4_free_cookie(fs_volume* volume, fs_vnode* vnode, void* _cookie) { Inode* inode = reinterpret_cast(vnode->private_node); - if (inode->Type() == S_IFDIR) + if (inode->Type() == S_IFDIR || inode->Type() == S_IFLNK) return B_OK; OpenFileCookie* cookie = reinterpret_cast(_cookie); @@ -234,6 +234,9 @@ nfs4_read(fs_volume* volume, fs_vnode* vnode, void* _cookie, off_t pos, if (inode->Type() == S_IFDIR) return B_IS_A_DIRECTORY; + if (inode->Type() == S_IFLNK) + return B_BAD_VALUE; + OpenFileCookie* cookie = reinterpret_cast(_cookie); return inode->Read(cookie, pos, buffer, length); From 21769ef60394a854df725a2ad2ca995c4daa2042 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Tue, 19 Jun 2012 03:20:39 +0200 Subject: [PATCH 058/252] Add dns_resolver module dns_resolver module provides a means for all kernel mode code to resolve DNS hostnames. --- build/jam/BuildSetup | 1 + build/jam/HaikuImage | 2 + headers/private/net/dns_resolver.h | 25 +++ src/add-ons/kernel/network/Jamfile | 1 + .../kernel/network/dns_resolver/Definitions.h | 23 +++ .../kernel/network/dns_resolver/Jamfile | 4 + .../dns_resolver/kernel_add_on/Jamfile | 9 + .../kernel_add_on/dns_resolver.cpp | 160 ++++++++++++++++++ .../network/dns_resolver/server/Jamfile | 16 ++ .../server/dns_resolver_server.rdef | 20 +++ .../network/dns_resolver/server/main.cpp | 107 ++++++++++++ 11 files changed, 368 insertions(+) create mode 100644 headers/private/net/dns_resolver.h create mode 100644 src/add-ons/kernel/network/dns_resolver/Definitions.h create mode 100644 src/add-ons/kernel/network/dns_resolver/Jamfile create mode 100644 src/add-ons/kernel/network/dns_resolver/kernel_add_on/Jamfile create mode 100644 src/add-ons/kernel/network/dns_resolver/kernel_add_on/dns_resolver.cpp create mode 100644 src/add-ons/kernel/network/dns_resolver/server/Jamfile create mode 100644 src/add-ons/kernel/network/dns_resolver/server/dns_resolver_server.rdef create mode 100644 src/add-ons/kernel/network/dns_resolver/server/main.cpp diff --git a/build/jam/BuildSetup b/build/jam/BuildSetup index b6fbcc1c5b..9136f0ddb7 100644 --- a/build/jam/BuildSetup +++ b/build/jam/BuildSetup @@ -1297,6 +1297,7 @@ if $(HAIKU_NO_WERROR) != 1 { EnableWerror src add-ons kernel generic ; # EnableWerror src add-ons kernel network datalink_protocols ; EnableWerror src add-ons kernel network devices ; + EnableWerror src add-ons kernel network dns_resolver ; EnableWerror src add-ons kernel network notifications ; EnableWerror src add-ons kernel network ppp ; EnableWerror src add-ons kernel network protocols ; diff --git a/build/jam/HaikuImage b/build/jam/HaikuImage index 0f44294dcd..0d2714b10b 100644 --- a/build/jam/HaikuImage +++ b/build/jam/HaikuImage @@ -106,6 +106,7 @@ PRIVATE_SYSTEM_LIBS = SYSTEM_SERVERS = app_server cddb_daemon debug_server input_server mail_daemon media_addon_server media_server midi_server mount_server net_server notification_server power_daemon print_server print_addon_server registrar syslog_daemon + dns_resolver_server ; SYSTEM_NETWORK_DEVICES = ethernet loopback ; @@ -651,6 +652,7 @@ AddFilesToHaikuImage system add-ons input_server filters : screen_saver shortcut_catcher ; AddFilesToHaikuImage system add-ons kernel network : notifications stack ; +AddFilesToHaikuImage system add-ons kernel network : dns_resolver ; AddFilesToHaikuImage system add-ons kernel network devices : $(SYSTEM_NETWORK_DEVICES) ; AddFilesToHaikuImage system add-ons kernel network datalink_protocols diff --git a/headers/private/net/dns_resolver.h b/headers/private/net/dns_resolver.h new file mode 100644 index 0000000000..179e9c2fe2 --- /dev/null +++ b/headers/private/net/dns_resolver.h @@ -0,0 +1,25 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ +#ifndef DNS_RESOLVER_H +#define DNS_RESOLVER_H + + +#include + + +#define DNS_RESOLVER_MODULE_NAME "network/dns_resolver/v1" + + +struct dns_resolver_module { + module_info module; + status_t (*dns_resolve)(const char* host, uint32* addr); +}; + + +#endif // DNS_RESOLVER_H + diff --git a/src/add-ons/kernel/network/Jamfile b/src/add-ons/kernel/network/Jamfile index 66d4448e41..7667873344 100644 --- a/src/add-ons/kernel/network/Jamfile +++ b/src/add-ons/kernel/network/Jamfile @@ -2,6 +2,7 @@ SubDir HAIKU_TOP src add-ons kernel network ; SubInclude HAIKU_TOP src add-ons kernel network datalink_protocols ; SubInclude HAIKU_TOP src add-ons kernel network devices ; +SubInclude HAIKU_TOP src add-ons kernel network dns_resolver ; SubInclude HAIKU_TOP src add-ons kernel network notifications ; SubInclude HAIKU_TOP src add-ons kernel network protocols ; SubInclude HAIKU_TOP src add-ons kernel network stack ; diff --git a/src/add-ons/kernel/network/dns_resolver/Definitions.h b/src/add-ons/kernel/network/dns_resolver/Definitions.h new file mode 100644 index 0000000000..407b2a436c --- /dev/null +++ b/src/add-ons/kernel/network/dns_resolver/Definitions.h @@ -0,0 +1,23 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ +#ifndef DEFINITIONS_H +#define DEFINITIONS_H + + +const char* kPortNameReq = "dns_resolver_req"; +const char* kPortNameRpl = "dns_resolver_rpl"; + +enum MsgCodes { + MsgResolveRequest = 1, + MsgResolveReply = 2, + MsgResolveError = 3 +}; + + +#endif // DEFINITIONS_H + diff --git a/src/add-ons/kernel/network/dns_resolver/Jamfile b/src/add-ons/kernel/network/dns_resolver/Jamfile new file mode 100644 index 0000000000..8dcbbeb2ea --- /dev/null +++ b/src/add-ons/kernel/network/dns_resolver/Jamfile @@ -0,0 +1,4 @@ +SubDir HAIKU_TOP src add-ons kernel network dns_resolver ; + +SubInclude HAIKU_TOP src add-ons kernel network dns_resolver kernel_add_on ; +SubInclude HAIKU_TOP src add-ons kernel network dns_resolver server ; diff --git a/src/add-ons/kernel/network/dns_resolver/kernel_add_on/Jamfile b/src/add-ons/kernel/network/dns_resolver/kernel_add_on/Jamfile new file mode 100644 index 0000000000..30bc8c5a89 --- /dev/null +++ b/src/add-ons/kernel/network/dns_resolver/kernel_add_on/Jamfile @@ -0,0 +1,9 @@ +SubDir HAIKU_TOP src add-ons kernel network dns_resolver kernel_add_on ; + +UsePrivateKernelHeaders ; + +SubDirHdrs [ FDirName $(SUBDIR) $(DOTDOT) ] ; + +KernelAddon dns_resolver : + dns_resolver.cpp +; diff --git a/src/add-ons/kernel/network/dns_resolver/kernel_add_on/dns_resolver.cpp b/src/add-ons/kernel/network/dns_resolver/kernel_add_on/dns_resolver.cpp new file mode 100644 index 0000000000..121c08c6c7 --- /dev/null +++ b/src/add-ons/kernel/network/dns_resolver/kernel_add_on/dns_resolver.cpp @@ -0,0 +1,160 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ + + +#include + +#include +#include +#include +#include + +#include "Definitions.h" + + +static mutex gPortLock; +static port_id gPortRequest = -1; +static port_id gPortReply = -1; + +static const int32 kQueueLength = 1; + + +static status_t +dns_resolver_repair() +{ + status_t result = B_OK; + + gPortRequest = create_port(kQueueLength, kPortNameReq); + if (gPortRequest < B_OK) + return gPortRequest; + + gPortReply = create_port(kQueueLength, kPortNameRpl); + if (gPortReply < B_OK) { + delete_port(gPortRequest); + return gPortReply; + } + + char path[256]; + if (find_directory(B_SYSTEM_SERVERS_DIRECTORY, static_cast(-1), + false, path, sizeof(path)) != B_OK) { + delete_port(gPortReply); + delete_port(gPortRequest); + return B_NAME_NOT_FOUND; + } + strlcat(path, "/dns_resolver_server", sizeof(path)); + + const char* args[] = { path, NULL }; + thread_id thread = load_image_etc(1, args, NULL, B_NORMAL_PRIORITY, + B_SYSTEM_TEAM, 0); + if (thread < B_OK) { + delete_port(gPortReply); + delete_port(gPortRequest); + return thread; + } + + set_port_owner(gPortRequest, thread); + set_port_owner(gPortReply, thread); + + result = resume_thread(thread); + if (result != B_OK) { + kill_thread(thread); + delete_port(gPortReply); + delete_port(gPortRequest); + return result; + } + + return B_OK; +} + + +static status_t +dns_resolver_init() +{ + mutex_init(&gPortLock, NULL); + return dns_resolver_repair(); +} + + +static status_t +dns_resolver_uninit() +{ + delete_port(gPortRequest); + delete_port(gPortReply); + mutex_destroy(&gPortLock); + + return B_OK; +} + + +static status_t +dns_resolve(const char* host, uint32* addr) +{ + mutex_lock(&gPortLock); + do { + status_t result = write_port(gPortRequest, MsgResolveRequest, host, + strlen(host) + 1); + if (result != B_OK) { + result = dns_resolver_repair(); + if (result != B_OK) { + mutex_unlock(&gPortLock); + return result; + } + + continue; + } + + int32 code; + result = read_port(gPortReply, &code, addr, sizeof(*addr)); + if (result < B_OK) { + result = dns_resolver_repair(); + if (result != B_OK) { + mutex_unlock(&gPortLock); + return result; + } + + continue; + } + mutex_unlock(&gPortLock); + + if (code == MsgResolveReply) + return B_OK; + else + return *addr; + + } while (true); +} + + +static status_t +dns_resolver_std_ops(int32 op, ...) +{ + switch (op) { + case B_MODULE_INIT: + return dns_resolver_init(); + case B_MODULE_UNINIT: + return dns_resolver_uninit(); + default: + return B_ERROR; + } +} + +static dns_resolver_module sDNSResolverModule = { + { + DNS_RESOLVER_MODULE_NAME, + 0, + dns_resolver_std_ops, + }, + + dns_resolve, +}; + +module_info* modules[] = { + (module_info*)&sDNSResolverModule, + NULL +}; + diff --git a/src/add-ons/kernel/network/dns_resolver/server/Jamfile b/src/add-ons/kernel/network/dns_resolver/server/Jamfile new file mode 100644 index 0000000000..e2fbbaad61 --- /dev/null +++ b/src/add-ons/kernel/network/dns_resolver/server/Jamfile @@ -0,0 +1,16 @@ +SubDir HAIKU_TOP src add-ons kernel network dns_resolver server ; + +UsePrivateKernelHeaders ; + +SubDirHdrs [ FDirName $(SUBDIR) $(DOTDOT) ] ; + +Application dns_resolver_server + : + main.cpp + + : + be $(TARGET_NETWORK_LIBS) + + : + dns_resolver_server.rdef +; diff --git a/src/add-ons/kernel/network/dns_resolver/server/dns_resolver_server.rdef b/src/add-ons/kernel/network/dns_resolver/server/dns_resolver_server.rdef new file mode 100644 index 0000000000..e0a0df5a41 --- /dev/null +++ b/src/add-ons/kernel/network/dns_resolver/server/dns_resolver_server.rdef @@ -0,0 +1,20 @@ +/* + * dns_resolver_server.rdef + */ + +resource app_signature "application/x-vnd.Haiku-dns-resolver-server"; + +resource app_flags B_EXCLUSIVE_LAUNCH | B_BACKGROUND_APP; + +resource app_version { + major = 1, + middle = 0, + minor = 0, + + variety = B_APPV_ALPHA, + internal = 0, + + short_info = "dns_resolver_server", + long_info = "dns_resolver_server ©2012 Haiku, Inc" +}; + diff --git a/src/add-ons/kernel/network/dns_resolver/server/main.cpp b/src/add-ons/kernel/network/dns_resolver/server/main.cpp new file mode 100644 index 0000000000..3b4a14ef19 --- /dev/null +++ b/src/add-ons/kernel/network/dns_resolver/server/main.cpp @@ -0,0 +1,107 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ + + +#include + +#include +#include + +#include +#include + +#include "Definitions.h" + + +status_t +resolve_dns(const char* host, uint32* addr) +{ + addrinfo* ai; + addrinfo* current; + status_t result = getaddrinfo(host, NULL, NULL, &ai); + if (result != B_OK) + return result; + + current = ai; + + while (current != NULL) { + if (current->ai_family == AF_INET) { + sockaddr_in* sin = reinterpret_cast(current->ai_addr); + *addr = sin->sin_addr.s_addr; + freeaddrinfo(ai); + return B_OK; + } + + current = current->ai_next; + } + + freeaddrinfo(ai); + return B_NAME_NOT_FOUND; +} + + +status_t +main_loop(port_id portReq, port_id portRpl) +{ + do { + ssize_t size = port_buffer_size(portReq); + if (size < B_OK) + return 0; + + void* buffer = malloc(size); + if (buffer == NULL) + return B_NO_MEMORY; + + int32 code; + status_t result = read_port(portReq, &code, buffer, size); + if (size < B_OK) { + free(buffer); + return 0; + } + + if (code != MsgResolveRequest) { + free(buffer); + continue; + } + + uint32 addr; + result = resolve_dns(reinterpret_cast(buffer), &addr); + free(buffer); + + if (result == B_OK) + result = write_port(portRpl, MsgResolveReply, &addr, sizeof(addr)); + else { + result = write_port(portRpl, MsgResolveError, &result, + sizeof(result)); + } + + if (result == B_BAD_PORT_ID) + return 0; + + } while (true); +} + + +int +main(int argc, char** argv) +{ + port_id portReq = find_port(kPortNameReq); + if (portReq == B_NAME_NOT_FOUND) { + fprintf(stderr, "%s\n", strerror(portReq)); + return portReq; + } + + port_id portRpl = find_port(kPortNameRpl); + if (portRpl == B_NAME_NOT_FOUND) { + fprintf(stderr, "%s\n", strerror(portRpl)); + return portRpl; + } + + return main_loop(portReq, portRpl); +} + From be46fd1b0fa92a2f6960e2779041d6e4f5aed82c Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Tue, 19 Jun 2012 22:23:00 +0200 Subject: [PATCH 059/252] nfs4: Send correct hostname when using AUTH_SYS --- .../kernel/file_systems/nfs4/RPCAuth.cpp | 2 +- src/system/kernel/util/Jamfile | 1 + src/system/kernel/util/hostname.cpp | 91 +++++++++++++++++++ 3 files changed, 93 insertions(+), 1 deletion(-) create mode 100644 src/system/kernel/util/hostname.cpp diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCAuth.cpp b/src/add-ons/kernel/file_systems/nfs4/RPCAuth.cpp index 6c6f1ba5d7..e9ce2aa365 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RPCAuth.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RPCAuth.cpp @@ -54,7 +54,7 @@ Auth::CreateSys() xdr.AddUInt(time(NULL)); char hostname[255]; - //if (gethostname(hostname, 255) < 0) + if (gethostname(hostname, 255) < 0) strcpy(hostname, "unknown"); xdr.AddString(hostname, 255); diff --git a/src/system/kernel/util/Jamfile b/src/system/kernel/util/Jamfile index 59ff30c7c6..23577a6981 100644 --- a/src/system/kernel/util/Jamfile +++ b/src/system/kernel/util/Jamfile @@ -4,6 +4,7 @@ UsePrivateHeaders [ FDirName kernel util ] ; KernelMergeObject kernel_util.o : AVLTreeBase.cpp + hostname.cpp kernel_cpp.cpp KernelReferenceable.cpp khash.cpp diff --git a/src/system/kernel/util/hostname.cpp b/src/system/kernel/util/hostname.cpp new file mode 100644 index 0000000000..676f16990e --- /dev/null +++ b/src/system/kernel/util/hostname.cpp @@ -0,0 +1,91 @@ +/* + * Copyright 2002-2007, Axel Dörfler, axeld@pinc-software.de. All rights reserved. + * Distributed under the terms of the MIT License. + */ + + +#include +#include +#include +#include + +#include +#include + +#include + + +static status_t +get_path(char *path, bool create) +{ + status_t status = find_directory(B_COMMON_SETTINGS_DIRECTORY, -1, create, + path, B_PATH_NAME_LENGTH); + if (status != B_OK) + return status; + + strlcat(path, "/network", B_PATH_NAME_LENGTH); + if (create) + mkdir(path, 0755); + strlcat(path, "/hostname", B_PATH_NAME_LENGTH); + return B_OK; +} + + +extern "C" int +sethostname(const char *hostName, size_t nameSize) +{ + char path[B_PATH_NAME_LENGTH]; + if (get_path(path, false) != B_OK) { + __set_errno(B_ERROR); + return -1; + } + + int file = open(path, O_WRONLY | O_CREAT, 0644); + if (file < 0) + return -1; + + nameSize = min_c(nameSize, MAXHOSTNAMELEN); + + if (write(file, hostName, nameSize) != (ssize_t)nameSize + || write(file, "\n", 1) != 1) { + close(file); + return -1; + } + + close(file); + return 0; +} + + +extern "C" int +gethostname(char *hostName, size_t nameSize) +{ + // look up hostname from network settings hostname file + + char path[B_PATH_NAME_LENGTH]; + if (get_path(path, false) != B_OK) { + __set_errno(B_ERROR); + return -1; + } + + int file = open(path, O_RDONLY); + if (file < 0) + return -1; + + nameSize = min_c(nameSize, MAXHOSTNAMELEN); + + int length = read(file, hostName, nameSize - 1); + close(file); + + if (length < 0) + return -1; + + hostName[length] = '\0'; + + char *end = strpbrk(hostName, "\r\n\t"); + if (end != NULL) + end[0] = '\0'; + + return 0; +} + From 800c2dd2d3cb7996eaa22908634c046f5214214b Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Tue, 19 Jun 2012 23:47:51 +0200 Subject: [PATCH 060/252] nfs4: Parse command line args Thist commit also makes inet_addr() accessible for the kernel and kernel modules. --- .../file_systems/nfs4/kernel_interface.cpp | 61 +++++- src/system/kernel/util/Jamfile | 1 + src/system/kernel/util/inet_addr.c | 198 ++++++++++++++++++ 3 files changed, 255 insertions(+), 5 deletions(-) create mode 100644 src/system/kernel/util/inet_addr.c 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 48fe7a956f..0d7e81ddbe 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -7,6 +7,10 @@ */ +#include +#include + +#include #include #include "Connection.h" @@ -35,23 +39,69 @@ sCreateNFS4Server(RPC::Server* serv) } +static status_t +sParseArguments(const char* _args, uint32* _ip, char* _path) +{ + if (_args == NULL) + return B_BAD_VALUE; + + char* args = strdup(_args); + char* path = strpbrk(args, ":"); + if (path == NULL) { + free(args); + return B_MISMATCHED_VALUES; + } + *path++ = '\0'; + + status_t result; + struct in_addr addr; + if (inet_aton(args, &addr) == 0) { + dns_resolver_module* dns; + result = get_module(DNS_RESOLVER_MODULE_NAME, + reinterpret_cast(&dns)); + if (result != B_OK) { + free(args); + return result; + } + + result = dns->dns_resolve(args, _ip); + put_module(DNS_RESOLVER_MODULE_NAME); + if (result != B_OK) { + free(args); + return result; + } + } else + *_ip = addr.s_addr; + *_ip = ntohl(*_ip); + + _path[255] = '\0'; + strncpy(_path, path, 255); + + free(args); + return B_OK; +} + + static status_t nfs4_mount(fs_volume* volume, const char* device, uint32 flags, const char* args, ino_t* _rootVnodeID) { status_t result; + uint32 ip; + char path[256]; + result = sParseArguments(args, &ip, path); + if (result != B_OK) + return result; + RPC::Server *server; - // hardcoded ip 192.168.1.70 - result = gRPCServerManager->Acquire(&server, 0xc0a80146, 2049, ProtocolUDP, + result = gRPCServerManager->Acquire(&server, ip, 2049, ProtocolUDP, sCreateNFS4Server); if (result != B_OK) return result; Filesystem* fs; - // hardcoded path - result = Filesystem::Mount(&fs, server, "haiku/src/add-ons/kernel", - volume->id); + result = Filesystem::Mount(&fs, server, path, volume->id); if (result != B_OK) { gRPCServerManager->Release(server); return result; @@ -295,6 +345,7 @@ nfs4_rewind_dir(fs_volume* volume, fs_vnode* vnode, void* _cookie) return B_OK; } + status_t nfs4_init() { diff --git a/src/system/kernel/util/Jamfile b/src/system/kernel/util/Jamfile index 23577a6981..831b0af209 100644 --- a/src/system/kernel/util/Jamfile +++ b/src/system/kernel/util/Jamfile @@ -5,6 +5,7 @@ UsePrivateHeaders [ FDirName kernel util ] ; KernelMergeObject kernel_util.o : AVLTreeBase.cpp hostname.cpp + inet_addr.c kernel_cpp.cpp KernelReferenceable.cpp khash.cpp diff --git a/src/system/kernel/util/inet_addr.c b/src/system/kernel/util/inet_addr.c new file mode 100644 index 0000000000..dca5d40cd1 --- /dev/null +++ b/src/system/kernel/util/inet_addr.c @@ -0,0 +1,198 @@ +/* + * Copyright (c) 1983, 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Portions Copyright (c) 1993 by Digital Equipment Corporation. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies, and that + * the name of Digital Equipment Corporation not be used in advertising or + * publicity pertaining to distribution of the document or software without + * specific, written prior permission. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT + * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Portions Copyright (c) 1996-1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include + +#include +#include + +#include + +/*% + * Ascii internet address interpretation routine. + * The value returned is in network order. + */ +in_addr_t +inet_addr(const char *cp) { + struct in_addr val; + + if (inet_aton(cp, &val)) + return (val.s_addr); + return (INADDR_NONE); +} + +/*% + * Check whether "cp" is a valid ascii representation + * of an Internet address and convert to a binary address. + * Returns 1 if the address is valid, 0 if not. + * This replaces inet_addr, the return value from which + * cannot distinguish between failure and a local broadcast address. + */ +int +inet_aton(const char *cp, struct in_addr *addr) { + u_long val; + int base, n; + char c; + u_int8_t parts[4]; + u_int8_t *pp = parts; + int digit; + + c = *cp; + for (;;) { + /* + * Collect number up to ``.''. + * Values are specified as for C: + * 0x=hex, 0=octal, isdigit=decimal. + */ + if (!isdigit((unsigned char)c)) + return (0); + val = 0; base = 10; digit = 0; + if (c == '0') { + c = *++cp; + if (c == 'x' || c == 'X') + base = 16, c = *++cp; + else { + base = 8; + digit = 1 ; + } + } + for (;;) { + if (isascii(c) && isdigit((unsigned char)c)) { + if (base == 8 && (c == '8' || c == '9')) + return (0); + val = (val * base) + (c - '0'); + c = *++cp; + digit = 1; + } else if (base == 16 && isascii(c) && + isxdigit((unsigned char)c)) { + val = (val << 4) | + (c + 10 - (islower((unsigned char)c) ? 'a' : 'A')); + c = *++cp; + digit = 1; + } else + break; + } + if (c == '.') { + /* + * Internet format: + * a.b.c.d + * a.b.c (with c treated as 16 bits) + * a.b (with b treated as 24 bits) + */ + if (pp >= parts + 3 || val > 0xffU) + return (0); + *pp++ = val; + c = *++cp; + } else + break; + } + /* + * Check for trailing characters. + */ + if (c != '\0' && (!isascii(c) || !isspace((unsigned char)c))) + return (0); + /* + * Did we get a valid digit? + */ + if (!digit) + return (0); + /* + * Concoct the address according to + * the number of parts specified. + */ + n = pp - parts + 1; + switch (n) { + case 1: /*%< a -- 32 bits */ + break; + + case 2: /*%< a.b -- 8.24 bits */ + if (val > 0xffffffU) + return (0); + val |= parts[0] << 24; + break; + + case 3: /*%< a.b.c -- 8.8.16 bits */ + if (val > 0xffffU) + return (0); + val |= (parts[0] << 24) | (parts[1] << 16); + break; + + case 4: /*%< a.b.c.d -- 8.8.8.8 bits */ + if (val > 0xffU) + return (0); + val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8); + break; + } + if (addr != NULL) + addr->s_addr = htonl(val); + return (1); +} + From 8b908ae4e86f13568949d5797004054d2138fe75 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Tue, 19 Jun 2012 23:56:24 +0200 Subject: [PATCH 061/252] nfs4: Fix parsing filesystem path in ReadInfo() --- src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp b/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp index 2913418884..339558ab05 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp @@ -209,9 +209,11 @@ Filesystem::ReadInfo(struct fs_info* info) info->flags = B_FS_IS_READONLY; const char* name = strrchr(fPath, '/'); - if (name != NULL) + if (name != NULL) { name++; - strncpy(info->volume_name, name, B_FILE_NAME_LENGTH); + strncpy(info->volume_name, name, B_FILE_NAME_LENGTH); + } else + strncpy(info->volume_name, fPath, B_FILE_NAME_LENGTH); return B_OK; } From 963a5e658a898f898f8c07c56d8f29a31d01b82a Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Wed, 20 Jun 2012 17:05:25 +0200 Subject: [PATCH 062/252] nfs4: Forbid accessing multiple NFS4 filesystems from one local mount Haiku assumes that a pair dev_t:ino_t uniquely identifies a file. That may not be the case if we allow multiple filesystems share one dev_t. --- .../kernel/file_systems/nfs4/Filehandle.h | 22 +++++++++ .../kernel/file_systems/nfs4/Filesystem.cpp | 14 ++++++ .../kernel/file_systems/nfs4/Filesystem.h | 46 +++++++++++-------- .../kernel/file_systems/nfs4/Inode.cpp | 42 +++++++++++++---- .../file_systems/nfs4/ReplyInterpreter.cpp | 12 +++++ 5 files changed, 108 insertions(+), 28 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Filehandle.h b/src/add-ons/kernel/file_systems/nfs4/Filehandle.h index 3fae5ef2d1..f8a64d3d76 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Filehandle.h +++ b/src/add-ons/kernel/file_systems/nfs4/Filehandle.h @@ -44,6 +44,14 @@ struct FileInfo { inline FileInfo& operator=(const FileInfo& fi); }; +struct FilesystemId { + uint64 fMajor; + uint64 fMinor; + + inline bool operator==(const FilesystemId& fsid) const; + inline bool operator!=(const FilesystemId& fsid) const; +}; + inline Filehandle::Filehandle() @@ -118,5 +126,19 @@ FileInfo::operator=(const FileInfo& fi) } +inline bool +FilesystemId::operator==(const FilesystemId& fsid) const +{ + return fMajor == fsid.fMajor && fMinor == fsid.fMinor; +} + + +inline bool +FilesystemId::operator!=(const FilesystemId& fsid) const +{ + return !operator==(fsid); +} + + #endif // FILEHANDLE_H diff --git a/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp b/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp index 339558ab05..a67600fea6 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp @@ -63,6 +63,9 @@ Filesystem::Mount(Filesystem** pfs, RPC::Server* serv, const char* fsPath, req.GetFH(); req.Access(); + Attribute attr[] = { FATTR4_FSID }; + req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); + status_t result = request.Send(); if (result != B_OK) return result; @@ -92,11 +95,22 @@ Filesystem::Mount(Filesystem** pfs, RPC::Server* serv, const char* fsPath, != (ACCESS4_READ | ACCESS4_LOOKUP)) return B_PERMISSION_DENIED; + AttrValue* values; + uint32 count; + result = reply.GetAttr(&values, &count); + if (result != B_OK || count < 1) + return result; + + // FATTR4_FSID is mandatory + FilesystemId* fsid = + reinterpret_cast(values[0].fData.fPointer); + Filesystem* fs = new(std::nothrow) Filesystem; fs->fPath = strdup(fsPath); memcpy(&fs->fRootFH, &fh, sizeof(Filehandle)); fs->fServer = serv; fs->fDevId = id; + fs->fFsId = *fsid; *pfs = fs; diff --git a/src/add-ons/kernel/file_systems/nfs4/Filesystem.h b/src/add-ons/kernel/file_systems/nfs4/Filesystem.h index 7000f4bd59..3ddc2ef575 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Filesystem.h +++ b/src/add-ons/kernel/file_systems/nfs4/Filesystem.h @@ -21,35 +21,38 @@ class InodeIdMap; class Filesystem { public: - static status_t Mount(Filesystem** pfs, RPC::Server* serv, - const char* path, dev_t id); - ~Filesystem(); + static status_t Mount(Filesystem** pfs, RPC::Server* serv, + const char* path, dev_t id); + ~Filesystem(); - status_t GetInode(ino_t id, Inode** inode); - Inode* CreateRootInode(); + status_t GetInode(ino_t id, Inode** inode); + Inode* CreateRootInode(); - status_t ReadInfo(struct fs_info* info); + status_t ReadInfo(struct fs_info* info); - inline RPC::Server* Server(); - inline NFS4Server* NFSServer(); + inline RPC::Server* Server(); + inline NFS4Server* NFSServer(); - inline uint64 AllocFileId(); + inline const FilesystemId& FsId() const; - inline dev_t DevId() const; - inline InodeIdMap* InoIdMap(); + inline uint64 AllocFileId(); + + inline dev_t DevId() const; + inline InodeIdMap* InoIdMap(); private: - Filesystem(); + Filesystem(); - const char* fPath; + const char* fPath; + FilesystemId fFsId; - Filehandle fRootFH; + Filehandle fRootFH; - RPC::Server* fServer; + RPC::Server* fServer; - vint64 fId; - dev_t fDevId; + vint64 fId; + dev_t fDevId; - InodeIdMap fInoIdMap; + InodeIdMap fInoIdMap; }; @@ -67,6 +70,13 @@ Filesystem::NFSServer() } +inline const FilesystemId& +Filesystem::FsId() const +{ + return fFsId; +} + + inline uint64 Filesystem::AllocFileId() { diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index 1a50bb6834..4149599b0b 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -42,7 +42,7 @@ Inode::CreateInode(Filesystem* fs, const FileInfo &fi, Inode** _inode) req.PutFH(inode->fHandle); - Attribute attr[] = { FATTR4_TYPE, FATTR4_FILEID }; + Attribute attr[] = { FATTR4_TYPE, FATTR4_FSID, FATTR4_FILEID }; req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); status_t result = request.Send(); @@ -64,20 +64,28 @@ Inode::CreateInode(Filesystem* fs, const FileInfo &fi, Inode** _inode) AttrValue* values; uint32 count; result = reply.GetAttr(&values, &count); - if (result != B_OK || count < 1) + if (result != B_OK || count < 2) return result; if (fi.fFileId == 0) { - if (count < 2 || values[1].fAttribute != FATTR4_FILEID) + if (count < 3 || values[2].fAttribute != FATTR4_FILEID) inode->fFileId = fs->AllocFileId(); else - inode->fFileId = values[1].fData.fValue64; + inode->fFileId = values[2].fData.fValue64; } else inode->fFileId = fi.fFileId; // FATTR4_TYPE is mandatory inode->fType = values[0].fData.fValue32; + // FATTR4_FSID is mandatory + FilesystemId* fsid = + reinterpret_cast(values[1].fData.fPointer); + if (*fsid != fs->FsId()) { + delete[] values; + return B_ENTRY_NOT_FOUND; + } + delete[] values; *_inode = inode; @@ -117,7 +125,7 @@ Inode::LookUp(const char* name, ino_t* id) req.GetFH(); - Attribute attr[] = { FATTR4_FILEID }; + Attribute attr[] = { FATTR4_FSID, FATTR4_FILEID }; req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); status_t result = request.Send(); @@ -154,11 +162,19 @@ Inode::LookUp(const char* name, ino_t* id) if (result != B_OK) return result; + // FATTR4_FSID is mandatory + FilesystemId* fsid = + reinterpret_cast(values[0].fData.fPointer); + if (*fsid != fFilesystem->FsId()) { + delete[] values; + return B_ENTRY_NOT_FOUND; + } + uint64 fileId; - if (count < 1 || values[0].fAttribute != FATTR4_FILEID) + if (count < 2 || values[1].fAttribute != FATTR4_FILEID) fileId = fFilesystem->AllocFileId(); else - fileId = values[0].fData.fValue64; + fileId = values[1].fData.fValue64; delete[] values; *id = _FileIdToInoT(fileId); @@ -646,7 +662,7 @@ Inode::_ReadDirOnce(DirEntry** dirents, uint32* count, uint64* cookie, req.PutFH(fHandle); - Attribute attr[] = { FATTR4_FILEID }; + Attribute attr[] = { FATTR4_FSID, FATTR4_FILEID }; req.ReadDir(*count, cookie, attr, sizeof(attr) / sizeof(Attribute)); status_t result = request.Send(); @@ -797,9 +813,15 @@ Inode::ReadDir(void* _buffer, uint32 size, uint32* _count, uint64* cookie) for (i = 0; i < min_c(this_count, *_count - count); i++) { struct dirent* de = reinterpret_cast(buffer + pos); + // FATTR4_FSID is mandatory + void* data = dirents[i].fAttrs[0].fData.fPointer; + FilesystemId* fsid = reinterpret_cast(data); + if (*fsid != fFilesystem->FsId()) + continue; + ino_t id; - if (dirents[i].fAttrCount == 1) - id = _FileIdToInoT(dirents[i].fAttrs[0].fData.fValue64); + if (dirents[i].fAttrCount == 2) + id = _FileIdToInoT(dirents[i].fAttrs[1].fData.fValue64); else id = _FileIdToInoT(fFilesystem->AllocFileId()); diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp index cd9378f523..5a1fb56977 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp @@ -337,6 +337,18 @@ ReplyInterpreter::_DecodeAttrs(XDR::ReadStream& str, AttrValue** attrs, current++; } + if (sIsAttrSet(FATTR4_FSID, bitmap, bcount)) { + values[current].fAttribute = FATTR4_FSID; + values[current].fFreePointer = true; + + FilesystemId fsid; + fsid.fMajor = stream.GetUHyper(); + fsid.fMinor = stream.GetUHyper(); + + values[current].fData.fPointer = new FilesystemId(fsid); + current++; + } + if (sIsAttrSet(FATTR4_LEASE_TIME, bitmap, bcount)) { values[current].fAttribute = FATTR4_LEASE_TIME; values[current].fData.fValue32 = stream.GetUInt(); From a90b62049ae560eab02b59a53adc428f4e5fb3b9 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Wed, 20 Jun 2012 17:06:56 +0200 Subject: [PATCH 063/252] nfs4: Fix parsing paths that begin with '/' --- src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp b/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp index a67600fea6..dd7f0f76ca 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp @@ -44,10 +44,14 @@ Filesystem::Mount(Filesystem** pfs, RPC::Server* serv, const char* fsPath, char* path = strdup(fsPath); char* pathStart = path; char* pathEnd; - while (pathStart != NULL) { + while (pathStart != NULL && pathStart[0] != '\0') { pathEnd = strpbrk(pathStart, "/"); if (pathEnd != NULL) *pathEnd = '\0'; + if (pathEnd == pathStart) { + pathStart++; + continue; + } req.LookUp(pathStart); @@ -106,7 +110,10 @@ Filesystem::Mount(Filesystem** pfs, RPC::Server* serv, const char* fsPath, reinterpret_cast(values[0].fData.fPointer); Filesystem* fs = new(std::nothrow) Filesystem; - fs->fPath = strdup(fsPath); + if (fsPath != NULL && fsPath[0] == '/') + fs->fPath = strdup(fsPath + 1); + else + fs->fPath = strdup(fsPath + 1); memcpy(&fs->fRootFH, &fh, sizeof(Filehandle)); fs->fServer = serv; fs->fDevId = id; From 47c4ae37512708eb7cd2e8c05ad60e196e7764ad Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Wed, 20 Jun 2012 19:20:49 +0200 Subject: [PATCH 064/252] nfs4: Fix ReadDir() bug when skipping inodes --- src/add-ons/kernel/file_systems/nfs4/Inode.cpp | 9 ++++++--- .../kernel/file_systems/nfs4/ReplyInterpreter.cpp | 3 ++- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index 4149599b0b..d49d143da3 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -801,6 +801,7 @@ Inode::ReadDir(void* _buffer, uint32 size, uint32* _count, uint64* cookie) cookie[1]--; } + bool overflow = false; while (count < *_count && !eof) { this_count = *_count - count; DirEntry* dirents; @@ -809,7 +810,7 @@ Inode::ReadDir(void* _buffer, uint32 size, uint32* _count, uint64* cookie) if (result != B_OK) return result; - uint32 i; + uint32 i, entries = 0; for (i = 0; i < min_c(this_count, *_count - count); i++) { struct dirent* de = reinterpret_cast(buffer + pos); @@ -828,16 +829,18 @@ Inode::ReadDir(void* _buffer, uint32 size, uint32* _count, uint64* cookie) const char* name = dirents[i].fName; if (_FillDirEntry(de, id, name, pos, size) == B_BUFFER_OVERFLOW) { eof = true; + overflow = true; break; } pos += de->d_reclen; + entries++; } delete[] dirents; - count += i; + count += entries; } - if (count == 0 && this_count > 0) + if (count == 0 && overflow) return B_BUFFER_OVERFLOW; *_count = count; diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp index 5a1fb56977..092b2ff01d 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp @@ -345,7 +345,8 @@ ReplyInterpreter::_DecodeAttrs(XDR::ReadStream& str, AttrValue** attrs, fsid.fMajor = stream.GetUHyper(); fsid.fMinor = stream.GetUHyper(); - values[current].fData.fPointer = new FilesystemId(fsid); + values[current].fData.fPointer = malloc(sizeof(fsid)); + memcpy(values[current].fData.fPointer, &fsid, sizeof(fsid)); current++; } From 19df56ac66b03acd52570ed050113652a5e93606 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Thu, 21 Jun 2012 03:26:20 +0200 Subject: [PATCH 065/252] nfs4: Add support for server migration --- .../kernel/file_systems/nfs4/Filesystem.cpp | 161 ++++++++++++++++-- .../kernel/file_systems/nfs4/Filesystem.h | 16 +- .../kernel/file_systems/nfs4/Inode.cpp | 130 +++++++++++--- .../file_systems/nfs4/ReplyInterpreter.cpp | 61 +++++++ .../file_systems/nfs4/ReplyInterpreter.h | 23 ++- .../file_systems/nfs4/kernel_interface.cpp | 6 +- 6 files changed, 351 insertions(+), 46 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp b/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp index dd7f0f76ca..3a561f05b5 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp @@ -11,14 +11,21 @@ #include -#include "Request.h" +#include +#include +#include "Request.h" #include "Inode.h" +extern RPC::ServerManager* gRPCServerManager; +extern RPC::ProgramData* CreateNFS4Server(RPC::Server* serv); + + Filesystem::Filesystem() : fPath(NULL), + fName(NULL), fId(1) { } @@ -26,10 +33,27 @@ Filesystem::Filesystem() Filesystem::~Filesystem() { + free(const_cast(fName)); free(const_cast(fPath)); } +static const char* +sGetPath(const char* root, const char* path) +{ + int slash = 0; + for (int i = 0; path[i] != '\0'; i++) { + if (path[i] != root[i] || root[i] == '\0') + break; + + if (path[i] == '/') + slash = i; + } + + return path + slash; +} + + status_t Filesystem::Mount(Filesystem** pfs, RPC::Server* serv, const char* fsPath, dev_t id) @@ -67,7 +91,7 @@ Filesystem::Mount(Filesystem** pfs, RPC::Server* serv, const char* fsPath, req.GetFH(); req.Access(); - Attribute attr[] = { FATTR4_FSID }; + Attribute attr[] = { FATTR4_FSID, FATTR4_FS_LOCATIONS }; req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); status_t result = request.Send(); @@ -110,15 +134,39 @@ Filesystem::Mount(Filesystem** pfs, RPC::Server* serv, const char* fsPath, reinterpret_cast(values[0].fData.fPointer); Filesystem* fs = new(std::nothrow) Filesystem; + + if (count == 2 && values[1].fAttribute == FATTR4_FS_LOCATIONS) { + FSLocations* locs = + reinterpret_cast(values[1].fData.fLocations); + + fs->fPath = strdup(locs->fRootPath); + + delete locs; + } else + fs->fPath = NULL; + + const char* name; if (fsPath != NULL && fsPath[0] == '/') - fs->fPath = strdup(fsPath + 1); - else - fs->fPath = strdup(fsPath + 1); + fsPath++; + name = strrchr(fsPath, '/'); + if (name != NULL) { + name++; + fs->fName = strdup(name); + } else + fs->fName = strdup(fsPath); + memcpy(&fs->fRootFH, &fh, sizeof(Filehandle)); fs->fServer = serv; fs->fDevId = id; fs->fFsId = *fsid; + FileInfo fi; + fi.fFH = fh; + fi.fParent = fh; + fi.fName = strdup("/"); + fi.fPath = strdup(sGetPath(fs->fPath, fsPath)); + fs->fRoot = fi; + *pfs = fs; return B_OK; @@ -149,14 +197,8 @@ Filesystem::GetInode(ino_t id, Inode** _inode) Inode* Filesystem::CreateRootInode() { - FileInfo fi; - fi.fFH = fRootFH; - fi.fParent = fRootFH; - fi.fName = strdup("/"); - fi.fPath = strdup(fPath); - Inode* inode; - status_t result = Inode::CreateInode(this, fi, &inode); + status_t result = Inode::CreateInode(this, fRoot, &inode); if (result == B_OK) return inode; else @@ -229,12 +271,95 @@ Filesystem::ReadInfo(struct fs_info* info) } info->flags = B_FS_IS_READONLY; - const char* name = strrchr(fPath, '/'); - if (name != NULL) { - name++; - strncpy(info->volume_name, name, B_FILE_NAME_LENGTH); - } else - strncpy(info->volume_name, fPath, B_FILE_NAME_LENGTH); + strncpy(info->volume_name, fName, B_FILE_NAME_LENGTH); + + return B_OK; +} + + +status_t +Filesystem::Migrate(const Filehandle& fh, const RPC::Server* serv) +{ + mutex_lock(&fMigrationLock); + if (serv != fServer) { + mutex_unlock(&fMigrationLock); + return B_OK; + } + + Request request(fServer); + RequestBuilder& req = request.Builder(); + + req.PutFH(fh); + Attribute attr[] = { FATTR4_FS_LOCATIONS }; + req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); + + status_t result = request.Send(); + if (result != B_OK) { + mutex_unlock(&fMigrationLock); + return result; + } + + ReplyInterpreter& reply = request.Reply(); + + result = reply.PutFH(); + if (result != B_OK) { + mutex_unlock(&fMigrationLock); + return result; + } + + AttrValue* values; + uint32 count; + result = reply.GetAttr(&values, &count); + if (result != B_OK || count < 1) { + mutex_unlock(&fMigrationLock); + return result; + } + + FSLocations* locs = + reinterpret_cast(values[0].fData.fLocations); + + dns_resolver_module* dns; + result = get_module(DNS_RESOLVER_MODULE_NAME, + reinterpret_cast(&dns)); + if (result != B_OK) { + mutex_unlock(&fMigrationLock); + return result; + } + + RPC::Server* server = fServer; + for (uint32 i = 0; i < locs->fCount; i++) { + for (uint32 j = 0; j < locs->fLocations[i].fCount; j++) { + uint32 ip; + struct in_addr addr; + if (inet_aton(locs->fLocations[i].fLocations[j], &addr) == 0) { + result = dns->dns_resolve(locs->fLocations[i].fLocations[j], + &ip); + if (result != B_OK) + continue; + } else + ip = addr.s_addr; + + if (gRPCServerManager->Acquire(&fServer, ip, 2049, + ProtocolUDP, CreateNFS4Server) == B_OK) { + + free(const_cast(fPath)); + fPath = strdup(locs->fLocations[j].fRootPath); + break; + } + } + } + + put_module(DNS_RESOLVER_MODULE_NAME); + delete locs; + + if (server == fServer) { + mutex_unlock(&fMigrationLock); + return B_ERROR; + } + + gRPCServerManager->Release(server); + + mutex_unlock(&fMigrationLock); return B_OK; } diff --git a/src/add-ons/kernel/file_systems/nfs4/Filesystem.h b/src/add-ons/kernel/file_systems/nfs4/Filesystem.h index 3ddc2ef575..ed11fc2f89 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Filesystem.h +++ b/src/add-ons/kernel/file_systems/nfs4/Filesystem.h @@ -30,9 +30,13 @@ public: status_t ReadInfo(struct fs_info* info); + status_t Migrate(const Filehandle& fh, + const RPC::Server* serv); + inline RPC::Server* Server(); inline NFS4Server* NFSServer(); + inline const char* Path() const; inline const FilesystemId& FsId() const; inline uint64 AllocFileId(); @@ -42,9 +46,12 @@ public: private: Filesystem(); - const char* fPath; FilesystemId fFsId; + const char* fPath; + mutex fMigrationLock; + const char* fName; + FileInfo fRoot; Filehandle fRootFH; RPC::Server* fServer; @@ -70,6 +77,13 @@ Filesystem::NFSServer() } +inline const char* +Filesystem::Path() const +{ + return fPath; +} + + inline const FilesystemId& Filesystem::FsId() const { diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index d49d143da3..9ce8efcc94 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -37,7 +37,8 @@ Inode::CreateInode(Filesystem* fs, const FileInfo &fi, Inode** _inode) inode->fPath = strdup(fi.fPath); do { - Request request(fs->Server()); + RPC::Server* serv = fs->Server(); + Request request(serv); RequestBuilder& req = request.Builder(); req.PutFH(inode->fHandle); @@ -57,6 +58,12 @@ Inode::CreateInode(Filesystem* fs, const FileInfo &fi, Inode** _inode) continue; } + // filesystem has been moved + if (reply.NFS4Error() == NFS4ERR_MOVED) { + fs->Migrate(inode->fHandle, serv); + continue; + } + result = reply.PutFH(); if (result != B_OK) return result; @@ -113,7 +120,8 @@ Inode::LookUp(const char* name, ino_t* id) } do { - Request request(fFilesystem->Server()); + RPC::Server* serv = fFilesystem->Server(); + Request request(serv); RequestBuilder& req = request.Builder(); req.PutFH(fHandle); @@ -140,6 +148,12 @@ Inode::LookUp(const char* name, ino_t* id) continue; } + // filesystem has been moved + if (reply.NFS4Error() == NFS4ERR_MOVED) { + fFilesystem->Migrate(fHandle, serv); + continue; + } + result = reply.PutFH(); if (result != B_OK) return result; @@ -206,7 +220,8 @@ Inode::ReadLink(void* buffer, size_t* length) return B_BAD_VALUE; do { - Request request(fFilesystem->Server()); + RPC::Server* serv = fFilesystem->Server(); + Request request(serv); RequestBuilder& req = request.Builder(); req.PutFH(fHandle); @@ -224,6 +239,12 @@ Inode::ReadLink(void* buffer, size_t* length) continue; } + // filesystem has been moved + if (reply.NFS4Error() == NFS4ERR_MOVED) { + fFilesystem->Migrate(fHandle, serv); + continue; + } + result = reply.PutFH(); if (result != B_OK) return result; @@ -241,7 +262,8 @@ status_t Inode::Access(int mode) { do { - Request request(fFilesystem->Server()); + RPC::Server* serv = fFilesystem->Server(); + Request request(serv); RequestBuilder& req = request.Builder(); req.PutFH(fHandle); @@ -259,6 +281,12 @@ Inode::Access(int mode) continue; } + // filesystem has been moved + if (reply.NFS4Error() == NFS4ERR_MOVED) { + fFilesystem->Migrate(fHandle, serv); + continue; + } + result = reply.PutFH(); if (result != B_OK) return result; @@ -293,7 +321,8 @@ status_t Inode::Stat(struct stat* st) { do { - Request request(fFilesystem->Server()); + RPC::Server* serv = fFilesystem->Server(); + Request request(serv); RequestBuilder& req = request.Builder(); req.PutFH(fHandle); @@ -315,6 +344,12 @@ Inode::Stat(struct stat* st) continue; } + // filesystem has been moved + if (reply.NFS4Error() == NFS4ERR_MOVED) { + fFilesystem->Migrate(fHandle, serv); + continue; + } + result = reply.PutFH(); if (result != B_OK) return result; @@ -419,7 +454,8 @@ Inode::Open(int mode, OpenFileCookie* cookie) do { cookie->fClientId = fFilesystem->NFSServer()->ClientId(); - Request request(fFilesystem->Server()); + RPC::Server* serv = fFilesystem->Server(); + Request request(serv); RequestBuilder& req = request.Builder(); cookie->fOwnerId = atomic_add64(&cookie->fLastOwnerId, 1); @@ -440,6 +476,12 @@ Inode::Open(int mode, OpenFileCookie* cookie) 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); @@ -501,7 +543,8 @@ Inode::Close(OpenFileCookie* cookie) fFilesystem->NFSServer()->RemoveOpenFile(cookie); do { - Request request(fFilesystem->Server()); + RPC::Server* serv = fFilesystem->Server(); + Request request(serv); RequestBuilder& req = request.Builder(); req.PutFH(fHandle); @@ -520,6 +563,12 @@ Inode::Close(OpenFileCookie* cookie) 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, @@ -553,7 +602,8 @@ Inode::Read(OpenFileCookie* cookie, off_t pos, void* buffer, size_t* _length) while (size < *_length && !eof) { do { - Request request(fFilesystem->Server()); + RPC::Server* serv = fFilesystem->Server(); + Request request(serv); RequestBuilder& req = request.Builder(); req.PutFH(fHandle); @@ -572,6 +622,12 @@ Inode::Read(OpenFileCookie* cookie, off_t pos, void* buffer, size_t* _length) 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, @@ -614,7 +670,8 @@ Inode::OpenDir(uint64* cookie) return B_NOT_A_DIRECTORY; do { - Request request(fFilesystem->Server()); + RPC::Server* serv = fFilesystem->Server(); + Request request(serv); RequestBuilder& req = request.Builder(); req.PutFH(fHandle); @@ -632,6 +689,12 @@ Inode::OpenDir(uint64* cookie) continue; } + // filesystem has been moved + if (reply.NFS4Error() == NFS4ERR_MOVED) { + fFilesystem->Migrate(fHandle, serv); + continue; + } + result = reply.PutFH(); if (result != B_OK) return result; @@ -657,7 +720,8 @@ Inode::_ReadDirOnce(DirEntry** dirents, uint32* count, uint64* cookie, bool* eof) { do { - Request request(fFilesystem->Server()); + RPC::Server* serv = fFilesystem->Server(); + Request request(serv); RequestBuilder& req = request.Builder(); req.PutFH(fHandle); @@ -677,6 +741,12 @@ Inode::_ReadDirOnce(DirEntry** dirents, uint32* count, uint64* cookie, continue; } + // filesystem has been moved + if (reply.NFS4Error() == NFS4ERR_MOVED) { + fFilesystem->Migrate(fHandle, serv); + continue; + } + result = reply.PutFH(); if (result != B_OK) return result; @@ -712,7 +782,8 @@ status_t Inode::_ReadDirUp(struct dirent* de, uint32 pos, uint32 size) { do { - Request request(fFilesystem->Server()); + RPC::Server* serv = fFilesystem->Server(); + Request request(serv); RequestBuilder& req = request.Builder(); req.PutFH(fHandle); @@ -733,6 +804,12 @@ Inode::_ReadDirUp(struct dirent* de, uint32 pos, uint32 size) continue; } + // filesystem has been moved + if (reply.NFS4Error() == NFS4ERR_MOVED) { + fFilesystem->Migrate(fHandle, serv); + continue; + } + result = reply.PutFH(); if (result != B_OK) return result; @@ -849,16 +926,10 @@ Inode::ReadDir(void* _buffer, uint32 size, uint32* _count, uint64* cookie) } -status_t -Inode::_LookUpFilehandle() +static status_t +sParsePath(RequestBuilder& req, uint32* count, const char* _path) { - Request request(fFilesystem->Server()); - RequestBuilder& req = request.Builder(); - - req.PutRootFH(); - - uint32 lookupCount = 0; - char* path = strdup(fPath); + char* path = strdup(_path); char* pathStart = path; char* pathEnd; while (pathStart != NULL) { @@ -873,10 +944,27 @@ Inode::_LookUpFilehandle() else pathStart = NULL; - lookupCount++; + (*count)++; } free(path); + return B_OK; +} + + +status_t +Inode::_LookUpFilehandle() +{ + Request request(fFilesystem->Server()); + RequestBuilder& req = request.Builder(); + + req.PutRootFH(); + + uint32 lookupCount = 0; + + sParsePath(req, &lookupCount, fFilesystem->Path()); + sParsePath(req, &lookupCount, fPath); + req.GetFH(); status_t result = request.Send(); diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp index 092b2ff01d..01129a5842 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp @@ -14,6 +14,22 @@ #include +FSLocation::~FSLocation() +{ + free(const_cast(fRootPath)); + for (uint32 i = 0; i < fCount; i++) + free(const_cast(fLocations[i])); + delete[] fLocations; +} + + +FSLocations::~FSLocations() +{ + free(const_cast(fRootPath)); + delete[] fLocations; +} + + AttrValue::AttrValue() : fFreePointer(false) @@ -25,6 +41,8 @@ AttrValue::~AttrValue() { if (fFreePointer) free(fData.fPointer); + if (fAttribute == FATTR4_FS_LOCATIONS) + delete fData.fLocations; } @@ -285,6 +303,30 @@ ReplyInterpreter::SetClientID(uint64* clientid, uint64* verifier) } +static const char* +sFlattenPathname(XDR::ReadStream& str) +{ + uint32 count = str.GetUInt(); + char* pathname = NULL; + uint32 size = 0; + for (uint32 i = 0; i < count; i++) { + const char* path = str.GetString(); + size += strlen(path) + 1; + if (pathname == NULL) { + pathname = reinterpret_cast(malloc(strlen(path + 1))); + pathname[0] = '\0'; + } else { + *pathname++ = '/'; + pathname = reinterpret_cast(realloc(pathname, size)); + } + strcat(pathname, path); + free(const_cast(path)); + } + + return pathname; +} + + status_t ReplyInterpreter::_DecodeAttrs(XDR::ReadStream& str, AttrValue** attrs, uint32* count) @@ -374,6 +416,25 @@ ReplyInterpreter::_DecodeAttrs(XDR::ReadStream& str, AttrValue** attrs, current++; } + if (sIsAttrSet(FATTR4_FS_LOCATIONS, bitmap, bcount)) { + values[current].fAttribute = FATTR4_FS_LOCATIONS; + + FSLocations* locs = new FSLocations; + locs->fRootPath = sFlattenPathname(stream); + locs->fCount = stream.GetUInt(); + locs->fLocations = new FSLocation[locs->fCount]; + for (uint32 i = 0; i < locs->fCount; i++) { + locs->fLocations[i].fRootPath = sFlattenPathname(stream); + locs->fLocations[i].fCount = stream.GetUInt(); + locs->fLocations[i].fLocations = + new const char*[locs->fLocations[i].fCount]; + for (uint32 j = 0; j < locs->fLocations[i].fCount; j++) + locs->fLocations[i].fLocations[j] = stream.GetString(); + } + values[current].fData.fLocations = locs; + current++; + } + if (sIsAttrSet(FATTR4_MAXREAD, bitmap, bcount)) { values[current].fAttribute = FATTR4_MAXREAD; values[current].fData.fValue64 = stream.GetUHyper(); diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h index b3f0901ece..f49c2252a7 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h @@ -15,6 +15,22 @@ #include "RPCReply.h" +struct FSLocation { + const char* fRootPath; + const char** fLocations; + uint32 fCount; + + ~FSLocation(); +}; + +struct FSLocations { + const char* fRootPath; + FSLocation* fLocations; + uint32 fCount; + + ~FSLocations(); +}; + struct AttrValue { AttrValue(); ~AttrValue(); @@ -22,9 +38,10 @@ struct AttrValue { uint8 fAttribute; bool fFreePointer; union { - uint32 fValue32; - uint64 fValue64; - void* fPointer; + uint32 fValue32; + uint64 fValue64; + void* fPointer; + FSLocations* fLocations; } fData; }; 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 0d7e81ddbe..4f48d66037 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -32,8 +32,8 @@ dprintf(const char* format, ...); RPC::ServerManager* gRPCServerManager; -static RPC::ProgramData* -sCreateNFS4Server(RPC::Server* serv) +RPC::ProgramData* +CreateNFS4Server(RPC::Server* serv) { return new NFS4Server(serv); } @@ -96,7 +96,7 @@ nfs4_mount(fs_volume* volume, const char* device, uint32 flags, RPC::Server *server; result = gRPCServerManager->Acquire(&server, ip, 2049, ProtocolUDP, - sCreateNFS4Server); + CreateNFS4Server); if (result != B_OK) return result; From be4c74ead31246bd9b332f83a9e298969385fc4e Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Thu, 21 Jun 2012 21:09:41 +0200 Subject: [PATCH 066/252] nfs4: close*() should wake all blocked operations --- .../kernel/file_systems/nfs4/Cookie.cpp | 86 +++++++++++++++++++ src/add-ons/kernel/file_systems/nfs4/Cookie.h | 61 +++++++++++++ .../kernel/file_systems/nfs4/Inode.cpp | 34 ++++---- src/add-ons/kernel/file_systems/nfs4/Inode.h | 33 +++---- src/add-ons/kernel/file_systems/nfs4/Jamfile | 1 + .../kernel/file_systems/nfs4/RPCServer.cpp | 17 ++++ .../kernel/file_systems/nfs4/RPCServer.h | 3 + .../file_systems/nfs4/ReplyInterpreter.cpp | 8 +- .../file_systems/nfs4/ReplyInterpreter.h | 4 +- .../kernel/file_systems/nfs4/Request.cpp | 59 ++++++++++--- .../kernel/file_systems/nfs4/Request.h | 8 +- .../file_systems/nfs4/RequestBuilder.cpp | 8 +- .../kernel/file_systems/nfs4/RequestBuilder.h | 5 +- .../file_systems/nfs4/kernel_interface.cpp | 21 +++-- 14 files changed, 279 insertions(+), 69 deletions(-) create mode 100644 src/add-ons/kernel/file_systems/nfs4/Cookie.cpp create mode 100644 src/add-ons/kernel/file_systems/nfs4/Cookie.h diff --git a/src/add-ons/kernel/file_systems/nfs4/Cookie.cpp b/src/add-ons/kernel/file_systems/nfs4/Cookie.cpp new file mode 100644 index 0000000000..e2cc986c43 --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/Cookie.cpp @@ -0,0 +1,86 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ + + +#include "Cookie.h" + +#include "Inode.h" +#include "Request.h" + + +vint64 OpenFileCookie::fLastOwnerId = 0; + + +Cookie::Cookie() + : + fRequests(NULL) +{ + mutex_init(&fRequestLock, NULL); +} + + +Cookie::~Cookie() +{ + mutex_destroy(&fRequestLock); +} + + +status_t +Cookie::RegisterRequest(RPC::Request* req) +{ + mutex_lock(&fRequestLock); + RequestEntry* ent = new RequestEntry; + if (ent == NULL) { + mutex_unlock(&fRequestLock); + return B_NO_MEMORY; + } + + ent->fRequest = req; + ent->fNext = fRequests; + fRequests = ent; + mutex_unlock(&fRequestLock); + return B_OK; +} + + +status_t +Cookie::UnregisterRequest(RPC::Request* req) +{ + mutex_lock(&fRequestLock); + RequestEntry* ent = fRequests; + RequestEntry* prev = NULL; + while (ent != NULL) { + if (ent->fRequest == req) { + if (prev == NULL) + fRequests = ent->fNext; + else + prev->fNext = ent->fNext; + delete ent; + } + + prev = ent; + ent = ent->fNext; + } + mutex_unlock(&fRequestLock); + return B_OK; +} + + +status_t +Cookie::CancelAll() +{ + mutex_lock(&fRequestLock); + RequestEntry* ent = fRequests; + while (ent != NULL) { + fInode->FileSystem()->Server()->WakeCall(ent->fRequest); + ent = ent->fNext; + } + mutex_unlock(&fRequestLock); + return B_OK; +} + diff --git a/src/add-ons/kernel/file_systems/nfs4/Cookie.h b/src/add-ons/kernel/file_systems/nfs4/Cookie.h new file mode 100644 index 0000000000..13671baee0 --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/Cookie.h @@ -0,0 +1,61 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ +#ifndef COOKIE_H +#define COOKIE_H + + +#include + +#include "Filesystem.h" + +class Inode; + +struct Cookie { + struct RequestEntry { + RPC::Request* fRequest; + RequestEntry* fNext; + }; + + Inode* fInode; + RequestEntry* fRequests; + mutex fRequestLock; + + Cookie(); + virtual ~Cookie(); + + status_t RegisterRequest(RPC::Request* req); + status_t UnregisterRequest(RPC::Request* req); + status_t CancelAll(); +}; + +struct OpenFileCookie : public Cookie { + uint64 fClientId; + + uint32 fMode; + + Filehandle fHandle; + uint32 fStateId[3]; + uint32 fStateSeq; + + uint32 fSequence; + + uint64 fOwnerId; + static vint64 fLastOwnerId; + + OpenFileCookie* fNext; + OpenFileCookie* fPrev; +}; + +struct OpenDirCookie : public Cookie { + uint64 fCookie; + uint64 fCookieVerf; +}; + + +#endif // COOKIE_H + diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index 9ce8efcc94..d4e9e20bb4 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -15,9 +15,6 @@ #include "Request.h" -vint64 OpenFileCookie::fLastOwnerId = 0; - - Inode::Inode() { } @@ -447,6 +444,7 @@ Inode::Open(int mode, OpenFileCookie* cookie) bool confirm; status_t result; + cookie->fInode = this; cookie->fHandle = fHandle; cookie->fMode = mode; cookie->fSequence = 0; @@ -610,7 +608,7 @@ Inode::Read(OpenFileCookie* cookie, off_t pos, void* buffer, size_t* _length) req.Read(cookie->fStateId, cookie->fStateSeq, pos + size, *_length - size); - status_t result = request.Send(); + status_t result = request.Send(cookie); if (result != B_OK) return result; @@ -664,7 +662,7 @@ Inode::Read(OpenFileCookie* cookie, off_t pos, void* buffer, size_t* _length) status_t -Inode::OpenDir(uint64* cookie) +Inode::OpenDir(OpenDirCookie* cookie) { if (fType != NF4DIR) return B_NOT_A_DIRECTORY; @@ -707,8 +705,9 @@ Inode::OpenDir(uint64* cookie) if (allowed & ACCESS4_READ != ACCESS4_READ) return B_PERMISSION_DENIED; - cookie[0] = 0; - cookie[1] = 2; + cookie->fInode = this; + cookie->fCookie = 0; + cookie->fCookieVerf = 2; return B_OK; } while (true); @@ -716,7 +715,7 @@ Inode::OpenDir(uint64* cookie) status_t -Inode::_ReadDirOnce(DirEntry** dirents, uint32* count, uint64* cookie, +Inode::_ReadDirOnce(DirEntry** dirents, uint32* count, OpenDirCookie* cookie, bool* eof) { do { @@ -727,9 +726,10 @@ Inode::_ReadDirOnce(DirEntry** dirents, uint32* count, uint64* cookie, req.PutFH(fHandle); Attribute attr[] = { FATTR4_FSID, FATTR4_FILEID }; - req.ReadDir(*count, cookie, attr, sizeof(attr) / sizeof(Attribute)); + req.ReadDir(*count, cookie->fCookie, cookie->fCookieVerf, attr, + sizeof(attr) / sizeof(Attribute)); - status_t result = request.Send(); + status_t result = request.Send(cookie); if (result != B_OK) return result; @@ -751,7 +751,8 @@ Inode::_ReadDirOnce(DirEntry** dirents, uint32* count, uint64* cookie, if (result != B_OK) return result; - return reply.ReadDir(cookie, dirents, count, eof); + return reply.ReadDir(&cookie->fCookie, &cookie->fCookieVerf, dirents, + count, eof); } while (true); } @@ -846,7 +847,8 @@ Inode::_ReadDirUp(struct dirent* de, uint32 pos, uint32 size) // When directories are cached client should store inode numbers it assigned // to directroy entries and use them consequently. status_t -Inode::ReadDir(void* _buffer, uint32 size, uint32* _count, uint64* cookie) +Inode::ReadDir(void* _buffer, uint32 size, uint32* _count, + OpenDirCookie* cookie) { uint32 count = 0; uint32 pos = 0; @@ -855,17 +857,17 @@ Inode::ReadDir(void* _buffer, uint32 size, uint32* _count, uint64* cookie) char* buffer = reinterpret_cast(_buffer); - if (cookie[0] == 0 && cookie[1] == 2 && count < *_count) { + if (cookie->fCookie == 0 && cookie->fCookieVerf == 2 && count < *_count) { struct dirent* de = reinterpret_cast(buffer + pos); _FillDirEntry(de, fFileId, ".", pos, size); pos += de->d_reclen; count++; - cookie[1]--; + cookie->fCookieVerf--; } - if (cookie[0] == 0 && cookie[1] == 1 && count < *_count) { + if (cookie->fCookie == 0 && cookie->fCookieVerf == 1 && count < *_count) { struct dirent* de = reinterpret_cast(buffer + pos); if (strcmp(fName, "/")) @@ -875,7 +877,7 @@ Inode::ReadDir(void* _buffer, uint32 size, uint32* _count, uint64* cookie) pos += de->d_reclen; count++; - cookie[1]--; + cookie->fCookieVerf--; } bool overflow = false; diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h b/src/add-ons/kernel/file_systems/nfs4/Inode.h index d60873a98a..c1e7464426 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -13,29 +13,12 @@ #include +#include "Cookie.h" #include "Filesystem.h" #include "NFS4Defs.h" #include "ReplyInterpreter.h" -struct OpenFileCookie { - uint64 fClientId; - - uint32 fMode; - - Filehandle fHandle; - uint32 fStateId[3]; - uint32 fStateSeq; - - uint32 fSequence; - - uint64 fOwnerId; - static vint64 fLastOwnerId; - - OpenFileCookie* fNext; - OpenFileCookie* fPrev; -}; - class Inode { public: static status_t CreateInode(Filesystem* fs, const FileInfo& fi, @@ -45,6 +28,7 @@ public: inline ino_t ID() const; inline mode_t Type() const; inline const char* Name() const; + inline Filesystem* FileSystem() const; status_t LookUp(const char* name, ino_t* id); status_t ReadLink(void* buffer, size_t* length); @@ -56,9 +40,9 @@ public: status_t Read(OpenFileCookie* cookie, off_t pos, void* buffer, size_t* length); - status_t OpenDir(uint64* cookie); + status_t OpenDir(OpenDirCookie* cookie); status_t ReadDir(void* buffer, uint32 size, - uint32* count, uint64* cookie); + uint32* count, OpenDirCookie* cookie); private: Inode(); @@ -66,7 +50,7 @@ private: status_t _LookUpFilehandle(); status_t _ReadDirOnce(DirEntry** dirents, uint32* count, - uint64* cookie, bool* eof); + OpenDirCookie* cookie, bool* eof); status_t _FillDirEntry(struct dirent* de, ino_t id, const char* name, uint32 pos, uint32 size); status_t _ReadDirUp(struct dirent* de, uint32 pos, @@ -119,5 +103,12 @@ Inode::Name() const } +inline Filesystem* +Inode::FileSystem() const +{ + return fFilesystem; +} + + #endif // INODE_H diff --git a/src/add-ons/kernel/file_systems/nfs4/Jamfile b/src/add-ons/kernel/file_systems/nfs4/Jamfile index a5ac6260ff..933b1e0112 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Jamfile +++ b/src/add-ons/kernel/file_systems/nfs4/Jamfile @@ -3,6 +3,7 @@ SubDir HAIKU_TOP src add-ons kernel file_systems nfs4 ; UsePrivateHeaders kernel ; KernelAddon nfs4 : + Cookie.cpp Connection.cpp Filesystem.cpp Inode.cpp diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp b/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp index 8edb3d84d1..e4556d744d 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp @@ -155,6 +155,7 @@ Server::SendCallAsync(Call* call, Reply** reply, Request** request) req->fReply = reply; req->fEvent.Init(&req->fEvent, NULL); req->fDone = false; + req->fError = B_OK; req->fNext = NULL; fRequests.AddRequest(req); @@ -185,6 +186,22 @@ Server::ResendCallAsync(Call* call, Request* req) } +status_t +Server::WakeCall(Request* request) +{ + Request* req = fRequests.FindRequest(request->fXID); + if (req == NULL) + return B_OK; + + request->fError = B_FILE_ERROR; + *request->fReply = NULL; + request->fDone = true; + request->fEvent.NotifyAll(); + + return B_OK; +} + + status_t Server::Repair() { diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCServer.h b/src/add-ons/kernel/file_systems/nfs4/RPCServer.h index c45765e63e..4d622d9905 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RPCServer.h +++ b/src/add-ons/kernel/file_systems/nfs4/RPCServer.h @@ -22,8 +22,10 @@ namespace RPC { struct Request { uint32 fXID; ConditionVariable fEvent; + bool fDone; Reply** fReply; + status_t fError; Request* fNext; }; @@ -62,6 +64,7 @@ public: inline status_t WaitCall(Request* request, bigtime_t time = kWaitTime); inline status_t CancelCall(Request* request); + status_t WakeCall(Request* request); status_t Repair(); diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp index 01129a5842..69ba2f9ad2 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp @@ -237,14 +237,14 @@ ReplyInterpreter::Read(void* buffer, uint32* size, bool* eof) status_t -ReplyInterpreter::ReadDir(uint64* cookie, DirEntry** dirents, uint32* _count, - bool* eof) +ReplyInterpreter::ReadDir(uint64* cookie, uint64* cookieVerf, + DirEntry** dirents, uint32* _count, bool* eof) { status_t res = _OperationError(OpReadDir); if (res != B_OK) return res; - cookie[1] = fReply->Stream().GetUHyper(); + *cookieVerf = fReply->Stream().GetUHyper(); bool isNext; uint32 count = 0; @@ -254,7 +254,7 @@ ReplyInterpreter::ReadDir(uint64* cookie, DirEntry** dirents, uint32* _count, isNext = fReply->Stream().GetBoolean(); while (isNext && count < *_count) { - cookie[0] = fReply->Stream().GetUHyper(); + *cookie = fReply->Stream().GetUHyper(); entries[count].fName = fReply->Stream().GetString(); _DecodeAttrs(fReply->Stream(), &entries[count].fAttrs, diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h index f49c2252a7..f2ed9168e1 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h @@ -75,8 +75,8 @@ public: inline status_t PutFH(); inline status_t PutRootFH(); status_t Read(void* buffer, uint32* size, bool* eof); - status_t ReadDir(uint64* cookie, DirEntry** dirents, - uint32* count, bool* eof); + status_t ReadDir(uint64* cookie, uint64* cookieVerf, + DirEntry** dirents, uint32* count, bool* eof); status_t ReadLink(void* buffer, uint32* size, uint32 maxSize); inline status_t Renew(); status_t SetClientID(uint64* clientid, uint64* verifier); diff --git a/src/add-ons/kernel/file_systems/nfs4/Request.cpp b/src/add-ons/kernel/file_systems/nfs4/Request.cpp index fdf9871086..9e39a36b05 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Request.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Request.cpp @@ -7,15 +7,16 @@ */ +#include "Inode.h" #include "Request.h" status_t -Request::Send() +Request::Send(Cookie* cookie) { switch (fServer->ID().fProtocol) { - case ProtocolUDP: return _SendUDP(); - case ProtocolTCP: return _SendTCP(); + case ProtocolUDP: return _SendUDP(cookie); + case ProtocolTCP: return _SendTCP(cookie); } return B_BAD_VALUE; @@ -23,41 +24,61 @@ Request::Send() status_t -Request::_SendUDP() +Request::_SendUDP(Cookie* cookie) { - RPC::Reply *rpl; + RPC::Reply *rpl = NULL; RPC::Request *rpc; status_t result = fServer->SendCallAsync(fBuilder.Request(), &rpl, &rpc); if (result != B_OK) return result; + if (cookie != NULL) + cookie->RegisterRequest(rpc); + result = fServer->WaitCall(rpc); if (result != B_OK) { int attempts = 1; while (result != B_OK && attempts++ < kRetryLimit) { result = fServer->ResendCallAsync(fBuilder.Request(), rpc); - if (result != B_OK) + if (result != B_OK) { + if (cookie != NULL) + cookie->UnregisterRequest(rpc); return result; + } result = fServer->WaitCall(rpc); } if (result != B_OK) { + if (cookie != NULL) + cookie->UnregisterRequest(rpc); fServer->CancelCall(rpc); delete rpc; return result; } } - return fReply.SetTo(rpl); + if (cookie != NULL) + cookie->UnregisterRequest(rpc); + + if (rpc->fError != B_OK) { + delete rpl; + result = rpc->fError; + delete rpc; + return result; + } else { + fReply.SetTo(rpl); + delete rpc; + return B_OK; + } } status_t -Request::_SendTCP() +Request::_SendTCP(Cookie* cookie) { - RPC::Reply *rpl; + RPC::Reply *rpl = NULL; RPC::Request *rpc; status_t result; @@ -71,8 +92,14 @@ Request::_SendTCP() continue; } + if (cookie != NULL) + cookie->RegisterRequest(rpc); + result = fServer->WaitCall(rpc); if (result != B_OK) { + if (cookie != NULL) + cookie->UnregisterRequest(rpc); + fServer->CancelCall(rpc); delete rpc; @@ -80,7 +107,19 @@ Request::_SendTCP() } } while (result != B_OK && attempts++ < kRetryLimit); - return fReply.SetTo(rpl); + if (cookie != NULL) + cookie->UnregisterRequest(rpc); + + if (rpc->fError != B_OK) { + delete rpl; + result = rpc->fError; + delete rpc; + return result; + } else { + fReply.SetTo(rpl); + delete rpc; + return B_OK; + }; } diff --git a/src/add-ons/kernel/file_systems/nfs4/Request.h b/src/add-ons/kernel/file_systems/nfs4/Request.h index 317bd3fbd4..cb8e5e02f4 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Request.h +++ b/src/add-ons/kernel/file_systems/nfs4/Request.h @@ -14,6 +14,8 @@ #include "RPCServer.h" +class Cookie; + class Request { public: inline Request(RPC::Server* serv); @@ -21,12 +23,12 @@ public: inline RequestBuilder& Builder(); inline ReplyInterpreter& Reply(); - status_t Send(); + status_t Send(Cookie* cookie = NULL); void Reset(); private: - status_t _SendUDP(); - status_t _SendTCP(); + status_t _SendUDP(Cookie* cookie); + status_t _SendTCP(Cookie* cookie); RPC::Server* fServer; diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp index 35bcb2c1fb..dbfdd377f8 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp @@ -267,8 +267,8 @@ RequestBuilder::Read(const uint32* id, uint32 stateSeq, uint64 pos, uint32 len) status_t -RequestBuilder::ReadDir(uint32 count, uint64* cookie, Attribute* attrs, - uint32 attrCount) +RequestBuilder::ReadDir(uint32 count, uint64 cookie, uint64 cookieVerf, + Attribute* attrs, uint32 attrCount) { (void)count; @@ -278,8 +278,8 @@ RequestBuilder::ReadDir(uint32 count, uint64* cookie, Attribute* attrs, return B_NO_MEMORY; fRequest->Stream().AddUInt(OpReadDir); - fRequest->Stream().AddUHyper(cookie[0]); - fRequest->Stream().AddUHyper(cookie[1]); + fRequest->Stream().AddUHyper(cookie); + fRequest->Stream().AddUHyper(cookieVerf); // consider predicting this values basing on count or buffer size fRequest->Stream().AddUInt(0x2000); diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h index a557c65344..12005dba89 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h @@ -40,8 +40,9 @@ public: status_t PutRootFH(); status_t Read(const uint32* id, uint32 stateSeq, uint64 pos, uint32 len); - status_t ReadDir(uint32 count, uint64* cookie, - Attribute* attrs, uint32 attrCount); + status_t ReadDir(uint32 count, uint64 cookie, + uint64 cookieVerf, Attribute* attrs, + uint32 attrCount); status_t ReadLink(); status_t Renew(uint64 clientId); status_t SetClientID(const RPC::Server* serv); 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 4f48d66037..6ed7b435e3 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -253,9 +253,15 @@ nfs4_open(fs_volume* volume, fs_vnode* vnode, int openMode, void** _cookie) static status_t -nfs4_close(fs_volume* volume, fs_vnode* vnode, void* cookie) +nfs4_close(fs_volume* volume, fs_vnode* vnode, void* _cookie) { - return B_OK; + Inode* inode = reinterpret_cast(vnode->private_node); + + if (inode->Type() == S_IFDIR || inode->Type() == S_IFLNK) + return B_OK; + + Cookie* cookie = reinterpret_cast(_cookie); + return cookie->CancelAll(); } @@ -296,7 +302,7 @@ nfs4_read(fs_volume* volume, fs_vnode* vnode, void* _cookie, off_t pos, static status_t nfs4_open_dir(fs_volume* volume, fs_vnode* vnode, void** _cookie) { - uint64* cookie = new(std::nothrow) uint64[2]; + OpenDirCookie* cookie = new(std::nothrow) OpenDirCookie; if (cookie == NULL) return B_NO_MEMORY; *_cookie = cookie; @@ -311,16 +317,17 @@ nfs4_open_dir(fs_volume* volume, fs_vnode* vnode, void** _cookie) static status_t -nfs4_close_dir(fs_volume* volume, fs_vnode* vnode, void* cookie) +nfs4_close_dir(fs_volume* volume, fs_vnode* vnode, void* _cookie) { - return B_OK; + Cookie* cookie = reinterpret_cast(_cookie); + return cookie->CancelAll(); } static status_t nfs4_free_dir_cookie(fs_volume* volume, fs_vnode* vnode, void* cookie) { - delete[] reinterpret_cast(cookie); + delete reinterpret_cast(cookie); return B_OK; } @@ -329,7 +336,7 @@ static status_t nfs4_read_dir(fs_volume* volume, fs_vnode* vnode, void* _cookie, struct dirent* buffer, size_t bufferSize, uint32* _num) { - uint64* cookie = reinterpret_cast(_cookie); + OpenDirCookie* cookie = reinterpret_cast(_cookie); Inode* inode = reinterpret_cast(vnode->private_node); return inode->ReadDir(buffer, bufferSize, _num, cookie); } From 1ec6b0c1f74d5cc239bf210740ad35b9479b8ef6 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Thu, 21 Jun 2012 21:57:42 +0200 Subject: [PATCH 067/252] nfs4: Add rename() hook --- .../kernel/file_systems/nfs4/Inode.cpp | 58 +++++++++++++++++++ src/add-ons/kernel/file_systems/nfs4/Inode.h | 2 + .../kernel/file_systems/nfs4/NFS4Defs.h | 2 + .../file_systems/nfs4/ReplyInterpreter.cpp | 22 ++++++- .../file_systems/nfs4/ReplyInterpreter.h | 9 +++ .../file_systems/nfs4/RequestBuilder.cpp | 33 +++++++++++ .../kernel/file_systems/nfs4/RequestBuilder.h | 2 + src/add-ons/kernel/file_systems/nfs4/XDR.cpp | 2 +- src/add-ons/kernel/file_systems/nfs4/XDR.h | 2 +- .../file_systems/nfs4/kernel_interface.cpp | 12 +++- 10 files changed, 140 insertions(+), 4 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index d4e9e20bb4..b663991c7a 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -210,6 +210,64 @@ Inode::LookUp(const char* name, ino_t* id) } +// Rename may cause some problems if filehandles are volatile and local Inode +// object exists for renamed node. It's stored filename will become invalid +// and, consequnetly, filehandle restoration will fail. Probably, it will +// be much easier to solve this problem if more metadata is cached. +status_t +Inode::Rename(Inode* from, Inode* to, const char* fromName, const char* toName) +{ + if (from->fFilesystem != to->fFilesystem) + return B_DONT_DO_THAT; + + do { + RPC::Server* serv = from->fFilesystem->Server(); + Request request(serv); + RequestBuilder& req = request.Builder(); + + req.PutFH(from->fHandle); + req.SaveFH(); + req.PutFH(to->fHandle); + req.Rename(fromName, toName); + + status_t result = request.Send(); + if (result != B_OK) + return result; + + ReplyInterpreter& reply = request.Reply(); + + // filehandle has expired + if (reply.NFS4Error() == NFS4ERR_FHEXPIRED) { + from->_LookUpFilehandle(); + to->_LookUpFilehandle(); + continue; + } + + // filesystem has been moved + if (reply.NFS4Error() == NFS4ERR_MOVED) { + from->fFilesystem->Migrate(from->fHandle, serv); + to->fFilesystem->Migrate(to->fHandle, serv); + continue; + } + + result = reply.PutFH(); + if (result != B_OK) + return result; + + result = reply.SaveFH(); + if (result != B_OK) + return result; + + result = reply.PutFH(); + if (result != B_OK) + return result; + + + return reply.Rename(); + } while (true); +} + + status_t Inode::ReadLink(void* buffer, size_t* length) { diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h b/src/add-ons/kernel/file_systems/nfs4/Inode.h index c1e7464426..0265dde6df 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -32,6 +32,8 @@ public: status_t LookUp(const char* name, ino_t* id); status_t ReadLink(void* buffer, size_t* length); + static status_t Rename(Inode* from, Inode* to, + const char* fromName, const char* toName); status_t Access(int mode); status_t Stat(struct stat* st); diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h index fefe9efb39..c6c7ce4b74 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h @@ -34,7 +34,9 @@ enum Opcode { OpRead = 25, OpReadDir = 26, OpReadLink = 27, + OpRename = 29, OpRenew = 30, + OpSaveFH = 32, OpSetClientID = 35, OpSetClientIDConfirm = 36 }; diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp index 69ba2f9ad2..0207d323c1 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp @@ -289,6 +289,26 @@ ReplyInterpreter::ReadLink(void* buffer, uint32* size, uint32 maxSize) return fReply->Stream().IsEOF() ? B_BAD_VALUE : B_OK; } + +status_t +ReplyInterpreter::Rename() +{ + status_t res = _OperationError(OpRename); + if (res != B_OK) + return res; + + fReply->Stream().GetBoolean(); + fReply->Stream().GetUHyper(); + fReply->Stream().GetUHyper(); + + fReply->Stream().GetBoolean(); + fReply->Stream().GetUHyper(); + fReply->Stream().GetUHyper(); + + return fReply->Stream().IsEOF() ? B_BAD_VALUE : B_OK; +} + + status_t ReplyInterpreter::SetClientID(uint64* clientid, uint64* verifier) { @@ -556,7 +576,7 @@ ReplyInterpreter::_NFS4ErrorToHaiku(uint32 x) case NFS4ERR_NOENT: return B_ENTRY_NOT_FOUND; case NFS4ERR_IO: return B_IO_ERROR; case NFS4ERR_NXIO: return B_DEVICE_NOT_FOUND; - case NFS4ERR_ACCESS: return B_PERMISSION_DENIED; + case NFS4ERR_ACCESS: return B_NOT_ALLOWED; case NFS4ERR_EXIST: return B_FILE_EXISTS; case NFS4ERR_XDEV: return B_CROSS_DEVICE_LINK; case NFS4ERR_NOTDIR: return B_NOT_A_DIRECTORY; diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h index f2ed9168e1..a96262973a 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h @@ -78,7 +78,9 @@ public: status_t ReadDir(uint64* cookie, uint64* cookieVerf, DirEntry** dirents, uint32* count, bool* eof); status_t ReadLink(void* buffer, uint32* size, uint32 maxSize); + status_t Rename(); inline status_t Renew(); + inline status_t SaveFH(); status_t SetClientID(uint64* clientid, uint64* verifier); inline status_t SetClientIDConfirm(); @@ -161,6 +163,13 @@ ReplyInterpreter::Renew() } +inline status_t +ReplyInterpreter::SaveFH() +{ + return _OperationError(OpSaveFH); +} + + inline status_t ReplyInterpreter::SetClientIDConfirm() { diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp index dbfdd377f8..628ea3f865 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp @@ -308,6 +308,24 @@ RequestBuilder::ReadLink() } +status_t +RequestBuilder::Rename(const char* from, const char* to) +{ + if (fProcedure != ProcCompound) + return B_BAD_VALUE; + if (fRequest == NULL) + return B_NO_MEMORY; + + fRequest->Stream().AddUInt(OpRename); + fRequest->Stream().AddString(from); + fRequest->Stream().AddString(to); + + fOpCount++; + + return B_OK; +} + + status_t RequestBuilder::Renew(uint64 clientId) { @@ -325,6 +343,21 @@ RequestBuilder::Renew(uint64 clientId) } +status_t +RequestBuilder::SaveFH() +{ + if (fProcedure != ProcCompound) + return B_BAD_VALUE; + if (fRequest == NULL) + return B_NO_MEMORY; + + fRequest->Stream().AddUInt(OpSaveFH); + fOpCount++; + + return B_OK; +} + + status_t RequestBuilder::SetClientID(const RPC::Server* serv) { diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h index 12005dba89..26823c4e39 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h @@ -44,7 +44,9 @@ public: uint64 cookieVerf, Attribute* attrs, uint32 attrCount); status_t ReadLink(); + status_t Rename(const char* from, const char* to); status_t Renew(uint64 clientId); + status_t SaveFH(); status_t SetClientID(const RPC::Server* serv); status_t SetClientIDConfirm(uint64 id, uint64 ver); diff --git a/src/add-ons/kernel/file_systems/nfs4/XDR.cpp b/src/add-ons/kernel/file_systems/nfs4/XDR.cpp index 73455c99b0..423d444e0f 100644 --- a/src/add-ons/kernel/file_systems/nfs4/XDR.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/XDR.cpp @@ -270,7 +270,7 @@ status_t WriteStream::AddString(const char* str, uint32 maxlen) { uint32 len = strlen(str); - uint32 size = min_c(maxlen, len); + uint32 size = maxlen == 0 ? len : min_c(maxlen, len); return AddOpaque(str, size); } diff --git a/src/add-ons/kernel/file_systems/nfs4/XDR.h b/src/add-ons/kernel/file_systems/nfs4/XDR.h index 6f9aee292b..5d5300e321 100644 --- a/src/add-ons/kernel/file_systems/nfs4/XDR.h +++ b/src/add-ons/kernel/file_systems/nfs4/XDR.h @@ -76,7 +76,7 @@ public: inline status_t AddBoolean(bool x); - status_t AddString(const char* str, uint32 maxlen); + status_t AddString(const char* str, uint32 maxlen = 0); status_t AddOpaque(const void* ptr, uint32 size); status_t AddOpaque(const WriteStream& stream); 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 6ed7b435e3..4598d8637a 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -212,6 +212,16 @@ nfs4_read_symlink(fs_volume* volume, fs_vnode* link, char* buffer, } +static status_t +nfs4_rename(fs_volume* volume, fs_vnode* fromDir, const char* fromName, + fs_vnode* toDir, const char* toName) +{ + Inode* fromInode = reinterpret_cast(fromDir->private_node); + Inode* toInode = reinterpret_cast(toDir->private_node); + return Inode::Rename(fromInode, toInode, fromName, toName); +} + + static status_t nfs4_access(fs_volume* volume, fs_vnode* vnode, int mode) { @@ -425,7 +435,7 @@ fs_vnode_ops gNFSv4VnodeOps = { NULL, // link() NULL, // unlink() - NULL, // rename() + nfs4_rename, nfs4_access, nfs4_read_stat, From 6fb3845b38c8ab73fe79bc92a16604bfd3b9d209 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Fri, 22 Jun 2012 01:17:28 +0200 Subject: [PATCH 068/252] nfs4: Add unlink() and remove_dir() hooks --- .../kernel/file_systems/nfs4/Inode.cpp | 41 +++++++++++++++++++ src/add-ons/kernel/file_systems/nfs4/Inode.h | 1 + .../kernel/file_systems/nfs4/NFS4Defs.h | 1 + .../file_systems/nfs4/ReplyInterpreter.cpp | 15 +++++++ .../file_systems/nfs4/ReplyInterpreter.h | 1 + .../file_systems/nfs4/RequestBuilder.cpp | 17 ++++++++ .../kernel/file_systems/nfs4/RequestBuilder.h | 1 + .../file_systems/nfs4/kernel_interface.cpp | 20 ++++++++- 8 files changed, 95 insertions(+), 2 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index b663991c7a..c45b663c6d 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -210,6 +210,47 @@ Inode::LookUp(const char* name, ino_t* id) } +// May cause problem similar to Rename (described below). When node's is has +// more than one hard link and we delete the name it stores for filehandle +// restoration node will inocorectly become unavailable. +status_t +Inode::Remove(const char* name) +{ + do { + RPC::Server* serv = fFilesystem->Server(); + Request request(serv); + RequestBuilder& req = request.Builder(); + + req.PutFH(fHandle); + req.Remove(name); + + status_t 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; + } + + result = reply.PutFH(); + if (result != B_OK) + return result; + + return reply.Remove(); + } while (true); +} + + // Rename may cause some problems if filehandles are volatile and local Inode // object exists for renamed node. It's stored filename will become invalid // and, consequnetly, filehandle restoration will fail. Probably, it will diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h b/src/add-ons/kernel/file_systems/nfs4/Inode.h index 0265dde6df..f47182387a 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -32,6 +32,7 @@ public: status_t LookUp(const char* name, ino_t* id); status_t ReadLink(void* buffer, size_t* length); + status_t Remove(const char* name); static status_t Rename(Inode* from, Inode* to, const char* fromName, const char* toName); status_t Access(int mode); diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h index c6c7ce4b74..7db013f6d2 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h @@ -34,6 +34,7 @@ enum Opcode { OpRead = 25, OpReadDir = 26, OpReadLink = 27, + OpRemove = 28, OpRename = 29, OpRenew = 30, OpSaveFH = 32, diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp index 0207d323c1..003e31f585 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp @@ -290,6 +290,21 @@ ReplyInterpreter::ReadLink(void* buffer, uint32* size, uint32 maxSize) } +status_t +ReplyInterpreter::Remove() +{ + status_t res = _OperationError(OpRemove); + if (res != B_OK) + return res; + + fReply->Stream().GetBoolean(); + fReply->Stream().GetUHyper(); + fReply->Stream().GetUHyper(); + + return fReply->Stream().IsEOF() ? B_BAD_VALUE : B_OK; +} + + status_t ReplyInterpreter::Rename() { diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h index a96262973a..ab295dfa7f 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h @@ -78,6 +78,7 @@ public: status_t ReadDir(uint64* cookie, uint64* cookieVerf, DirEntry** dirents, uint32* count, bool* eof); status_t ReadLink(void* buffer, uint32* size, uint32 maxSize); + status_t Remove(); status_t Rename(); inline status_t Renew(); inline status_t SaveFH(); diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp index 628ea3f865..c0901baaae 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp @@ -308,6 +308,23 @@ RequestBuilder::ReadLink() } +status_t +RequestBuilder::Remove(const char* file) +{ + if (fProcedure != ProcCompound) + return B_BAD_VALUE; + if (fRequest == NULL) + return B_NO_MEMORY; + + fRequest->Stream().AddUInt(OpRemove); + fRequest->Stream().AddString(file); + + fOpCount++; + + return B_OK; +} + + status_t RequestBuilder::Rename(const char* from, const char* to) { diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h index 26823c4e39..61c1d19daa 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h @@ -44,6 +44,7 @@ public: uint64 cookieVerf, Attribute* attrs, uint32 attrCount); status_t ReadLink(); + status_t Remove(const char* file); status_t Rename(const char* from, const char* to); status_t Renew(uint64 clientId); status_t SaveFH(); 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 4598d8637a..adf6d19eb9 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -212,6 +212,14 @@ nfs4_read_symlink(fs_volume* volume, fs_vnode* link, char* buffer, } +static status_t +nfs4_unlink(fs_volume* volume, fs_vnode* dir, const char* name) +{ + Inode* inode = reinterpret_cast(dir->private_node); + return inode->Remove(name); +} + + static status_t nfs4_rename(fs_volume* volume, fs_vnode* fromDir, const char* fromName, fs_vnode* toDir, const char* toName) @@ -309,6 +317,14 @@ nfs4_read(fs_volume* volume, fs_vnode* vnode, void* _cookie, off_t pos, } +static status_t +nfs4_remove_dir(fs_volume* volume, fs_vnode* parent, const char* name) +{ + Inode* inode = reinterpret_cast(parent->private_node); + return inode->Remove(name); +} + + static status_t nfs4_open_dir(fs_volume* volume, fs_vnode* vnode, void** _cookie) { @@ -434,7 +450,7 @@ fs_vnode_ops gNFSv4VnodeOps = { NULL, // create_symlink() NULL, // link() - NULL, // unlink() + nfs4_unlink, nfs4_rename, nfs4_access, @@ -452,7 +468,7 @@ fs_vnode_ops gNFSv4VnodeOps = { /* directory operations */ NULL, // create_dir() - NULL, // remove_dir() + nfs4_remove_dir, nfs4_open_dir, nfs4_close_dir, nfs4_free_dir_cookie, From cf511f2446a526785babcef7c74793911266cf53 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Fri, 22 Jun 2012 02:08:07 +0200 Subject: [PATCH 069/252] nfs4: unlink() and remove_dir() should check node type --- .../kernel/file_systems/nfs4/Inode.cpp | 26 +++++++++++++++- src/add-ons/kernel/file_systems/nfs4/Inode.h | 2 +- .../kernel/file_systems/nfs4/NFS4Defs.h | 3 +- .../file_systems/nfs4/ReplyInterpreter.h | 8 +++++ .../file_systems/nfs4/RequestBuilder.cpp | 31 +++++++++++++++++++ .../kernel/file_systems/nfs4/RequestBuilder.h | 2 ++ .../file_systems/nfs4/kernel_interface.cpp | 4 +-- 7 files changed, 71 insertions(+), 5 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index c45b663c6d..f7c837c35b 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -214,13 +214,21 @@ Inode::LookUp(const char* name, ino_t* id) // more than one hard link and we delete the name it stores for filehandle // restoration node will inocorectly become unavailable. status_t -Inode::Remove(const char* name) +Inode::Remove(const char* name, FileType type) { do { RPC::Server* serv = fFilesystem->Server(); Request request(serv); RequestBuilder& req = request.Builder(); + req.PutFH(fHandle); + req.LookUp(name); + AttrValue attr; + attr.fAttribute = FATTR4_TYPE; + attr.fFreePointer = false; + attr.fData.fValue32 = type; + req.Verify(&attr, 1); + req.PutFH(fHandle); req.Remove(name); @@ -242,6 +250,22 @@ Inode::Remove(const char* name) continue; } + result = reply.PutFH(); + if (result != B_OK) + return result; + + result = reply.LookUp(); + if (result != B_OK) + return result; + + result = reply.Verify(); + if (result == NFS4ERR_NOT_SAME && type == NF4REG) + return B_IS_A_DIRECTORY; + if (result == NFS4ERR_NOT_SAME && type == NF4DIR) + return B_NOT_A_DIRECTORY; + if (result != B_OK) + return result; + result = reply.PutFH(); if (result != B_OK) return result; diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h b/src/add-ons/kernel/file_systems/nfs4/Inode.h index f47182387a..3f1498eecb 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -32,7 +32,7 @@ public: status_t LookUp(const char* name, ino_t* id); status_t ReadLink(void* buffer, size_t* length); - status_t Remove(const char* name); + status_t Remove(const char* name, FileType type); static status_t Rename(Inode* from, Inode* to, const char* fromName, const char* toName); status_t Access(int mode); diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h index 7db013f6d2..84d9b934a5 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h @@ -39,7 +39,8 @@ enum Opcode { OpRenew = 30, OpSaveFH = 32, OpSetClientID = 35, - OpSetClientIDConfirm = 36 + OpSetClientIDConfirm = 36, + OpVerify = 37 }; enum Access { diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h index ab295dfa7f..b0b3ba1411 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h @@ -84,6 +84,7 @@ public: inline status_t SaveFH(); status_t SetClientID(uint64* clientid, uint64* verifier); inline status_t SetClientIDConfirm(); + inline status_t Verify(); private: void _ParseHeader(); @@ -178,5 +179,12 @@ ReplyInterpreter::SetClientIDConfirm() } +inline status_t +ReplyInterpreter::Verify() +{ + return _OperationError(OpVerify); +} + + #endif // REPLYINTERPRETER_H diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp index c0901baaae..e28bce3916 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp @@ -432,6 +432,37 @@ RequestBuilder::SetClientIDConfirm(uint64 id, uint64 ver) } +status_t +RequestBuilder::Verify(AttrValue* attr, uint32 count) +{ + if (fProcedure != ProcCompound) + return B_BAD_VALUE; + if (fRequest == NULL) + return B_NO_MEMORY; + + fRequest->Stream().AddUInt(OpVerify); + + Attribute* attrs = + reinterpret_cast(malloc(sizeof(Attribute) * count)); + for (uint32 i = 0; i < count; i++) + attrs[i] = static_cast(attr[i].fAttribute); + _AttrBitmap(fRequest->Stream(), attrs, count); + free(attrs); + + uint32 i = 0; + XDR::WriteStream str; + if (i < count && attr[i].fAttribute == FATTR4_TYPE) { + str.AddUInt(attr[i].fData.fValue32); + i++; + } + + fRequest->Stream().AddOpaque(str); + fOpCount++; + + return B_OK; +} + + RPC::Call* RequestBuilder::Request() { diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h index 61c1d19daa..795d6106be 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h @@ -12,6 +12,7 @@ #include #include "NFS4Defs.h" +#include "ReplyInterpreter.h" #include "RPCCall.h" #include "RPCServer.h" #include "XDR.h" @@ -50,6 +51,7 @@ public: status_t SaveFH(); status_t SetClientID(const RPC::Server* serv); status_t SetClientIDConfirm(uint64 id, uint64 ver); + status_t Verify(AttrValue* attr, uint32 count); RPC::Call* Request(); 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 adf6d19eb9..f784dbf740 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -216,7 +216,7 @@ static status_t nfs4_unlink(fs_volume* volume, fs_vnode* dir, const char* name) { Inode* inode = reinterpret_cast(dir->private_node); - return inode->Remove(name); + return inode->Remove(name, NF4REG); } @@ -321,7 +321,7 @@ static status_t nfs4_remove_dir(fs_volume* volume, fs_vnode* parent, const char* name) { Inode* inode = reinterpret_cast(parent->private_node); - return inode->Remove(name); + return inode->Remove(name, NF4DIR); } From c0de7aca1ccdb82519b67c63dfc5f4586fb9b368 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Fri, 22 Jun 2012 02:27:49 +0200 Subject: [PATCH 070/252] nfs4: Add link() hook --- .../kernel/file_systems/nfs4/Inode.cpp | 50 +++++++++++++++++++ src/add-ons/kernel/file_systems/nfs4/Inode.h | 1 + .../kernel/file_systems/nfs4/NFS4Defs.h | 1 + .../file_systems/nfs4/ReplyInterpreter.cpp | 15 ++++++ .../file_systems/nfs4/ReplyInterpreter.h | 1 + .../file_systems/nfs4/RequestBuilder.cpp | 18 +++++++ .../kernel/file_systems/nfs4/RequestBuilder.h | 1 + .../file_systems/nfs4/kernel_interface.cpp | 11 +++- 8 files changed, 97 insertions(+), 1 deletion(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index f7c837c35b..2d73127b89 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -210,6 +210,56 @@ Inode::LookUp(const char* name, ino_t* id) } +status_t +Inode::Link(Inode* dir, const char* name) +{ + do { + RPC::Server* serv = fFilesystem->Server(); + Request request(serv); + RequestBuilder& req = request.Builder(); + + req.PutFH(fHandle); + req.SaveFH(); + req.PutFH(dir->fHandle); + req.Link(name); + + status_t result = request.Send(); + if (result != B_OK) + return result; + + ReplyInterpreter& reply = request.Reply(); + + // filehandle has expired + if (reply.NFS4Error() == NFS4ERR_FHEXPIRED) { + _LookUpFilehandle(); + dir->_LookUpFilehandle(); + continue; + } + + // filesystem has been moved + if (reply.NFS4Error() == NFS4ERR_MOVED) { + fFilesystem->Migrate(fHandle, serv); + dir->fFilesystem->Migrate(dir->fHandle, serv); + continue; + } + + result = reply.PutFH(); + if (result != B_OK) + return result; + + result = reply.SaveFH(); + if (result != B_OK) + return result; + + result = reply.PutFH(); + if (result != B_OK) + return result; + + return reply.Link(); + } while (true); +} + + // May cause problem similar to Rename (described below). When node's is has // more than one hard link and we delete the name it stores for filehandle // restoration node will inocorectly become unavailable. diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h b/src/add-ons/kernel/file_systems/nfs4/Inode.h index 3f1498eecb..1809604c27 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -32,6 +32,7 @@ public: status_t LookUp(const char* name, ino_t* id); status_t ReadLink(void* buffer, size_t* length); + status_t Link(Inode* dir, const char* name); status_t Remove(const char* name, FileType type); static status_t Rename(Inode* from, Inode* to, const char* fromName, const char* toName); diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h index 84d9b934a5..8a07f035c9 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h @@ -25,6 +25,7 @@ enum Opcode { OpClose = 4, OpGetAttr = 9, OpGetFH = 10, + OpLink = 11, OpLookUp = 15, OpLookUpUp = 16, OpOpen = 18, diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp index 003e31f585..3e133faf48 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp @@ -173,6 +173,21 @@ ReplyInterpreter::GetFH(Filehandle* fh) } +status_t +ReplyInterpreter::Link() +{ + status_t res = _OperationError(OpLink); + if (res != B_OK) + return res; + + fReply->Stream().GetBoolean(); + fReply->Stream().GetUHyper(); + fReply->Stream().GetUHyper(); + + return fReply->Stream().IsEOF() ? B_BAD_VALUE : B_OK; +} + + status_t ReplyInterpreter::Open(uint32* id, uint32* seq, bool* confirm) { diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h index b0b3ba1411..51fd364514 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h @@ -68,6 +68,7 @@ public: status_t Close(); status_t GetAttr(AttrValue** attrs, uint32* count); status_t GetFH(Filehandle* fh); + status_t Link(); inline status_t LookUp(); inline status_t LookUpUp(); status_t Open(uint32* id, uint32* seq, bool* confirm); diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp index e28bce3916..4ce72edc8e 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp @@ -118,6 +118,24 @@ RequestBuilder::GetFH() } +status_t +RequestBuilder::Link(const char* name) +{ + if (fProcedure != ProcCompound) + return B_BAD_VALUE; + if (fRequest == NULL) + return B_NO_MEMORY; + if (name == NULL) + return B_BAD_VALUE; + + fRequest->Stream().AddUInt(OpLink); + fRequest->Stream().AddString(name); + fOpCount++; + + return B_OK; +} + + status_t RequestBuilder::LookUp(const char* name) { diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h index 795d6106be..9710cf171e 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h @@ -30,6 +30,7 @@ public: uint32 stateSeq); status_t GetAttr(Attribute* attrs, uint32 count); status_t GetFH(); + status_t Link(const char* name); status_t LookUp(const char* name); status_t LookUpUp(); status_t Open(OpenClaim claim, uint32 seq, 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 f784dbf740..e8f7b2949f 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -212,6 +212,15 @@ nfs4_read_symlink(fs_volume* volume, fs_vnode* link, char* buffer, } +static status_t +nfs4_link(fs_volume* volume, fs_vnode* dir, const char* name, fs_vnode* vnode) +{ + Inode* inode = reinterpret_cast(vnode->private_node); + Inode* dirInode = reinterpret_cast(dir->private_node); + return inode->Link(dirInode, name); +} + + static status_t nfs4_unlink(fs_volume* volume, fs_vnode* dir, const char* name) { @@ -449,7 +458,7 @@ fs_vnode_ops gNFSv4VnodeOps = { nfs4_read_symlink, NULL, // create_symlink() - NULL, // link() + nfs4_link, nfs4_unlink, nfs4_rename, From f5baf2ef9f3afe4df5e1565ba2651a0ae3ea38a9 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Fri, 22 Jun 2012 02:57:29 +0200 Subject: [PATCH 071/252] nfs4: Add create_symlink() hook --- .../kernel/file_systems/nfs4/Inode.cpp | 43 ++++++++++++ src/add-ons/kernel/file_systems/nfs4/Inode.h | 4 ++ .../kernel/file_systems/nfs4/NFS4Defs.h | 1 + .../file_systems/nfs4/ReplyInterpreter.cpp | 19 +++++ .../file_systems/nfs4/ReplyInterpreter.h | 1 + .../file_systems/nfs4/RequestBuilder.cpp | 70 +++++++++++++++---- .../kernel/file_systems/nfs4/RequestBuilder.h | 5 ++ .../file_systems/nfs4/kernel_interface.cpp | 11 ++- 8 files changed, 138 insertions(+), 16 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index 2d73127b89..a73837e37d 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -383,6 +383,49 @@ Inode::Rename(Inode* from, Inode* to, const char* fromName, const char* toName) } +status_t +Inode::CreateLink(const char* name, const char* path, int mode) +{ + do { + RPC::Server* serv = fFilesystem->Server(); + Request request(serv); + RequestBuilder& req = request.Builder(); + + req.PutFH(fHandle); + + AttrValue attr; + attr.fAttribute = FATTR4_MODE; + attr.fFreePointer = false; + attr.fData.fValue32 = mode; + req.Create(NF4LNK, name, path, &attr, 1); + + status_t 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; + } + + result = reply.PutFH(); + if (result != B_OK) + return result; + + return reply.Create(); + } while (true); +} + + status_t Inode::ReadLink(void* buffer, size_t* length) { diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h b/src/add-ons/kernel/file_systems/nfs4/Inode.h index 1809604c27..89caa2c39c 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -31,7 +31,11 @@ public: inline Filesystem* FileSystem() const; status_t LookUp(const char* name, ino_t* id); + + status_t CreateLink(const char* name, const char* path, + int mode); status_t ReadLink(void* buffer, size_t* length); + status_t Link(Inode* dir, const char* name); status_t Remove(const char* name, FileType type); static status_t Rename(Inode* from, Inode* to, diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h index 8a07f035c9..548992be91 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h @@ -23,6 +23,7 @@ enum Procedure { enum Opcode { OpAccess = 3, OpClose = 4, + OpCreate = 6, OpGetAttr = 9, OpGetFH = 10, OpLink = 11, diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp index 3e133faf48..dd03e0ef81 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp @@ -122,6 +122,25 @@ ReplyInterpreter::Close() } +status_t +ReplyInterpreter::Create() +{ + status_t res = _OperationError(OpCreate); + if (res != B_OK) + return res; + + fReply->Stream().GetBoolean(); + fReply->Stream().GetUHyper(); + fReply->Stream().GetUHyper(); + uint32 count = fReply->Stream().GetUInt(); + for (uint32 i; i < count; i++) + fReply->Stream().GetUInt(); + + return fReply->Stream().IsEOF() ? B_BAD_VALUE : B_OK; +} + + + // Bit Twiddling Hacks // http://graphics.stanford.edu/~seander/bithacks.html static inline uint32 sCountBits(uint32 v) diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h index 51fd364514..9c22a5e55b 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h @@ -66,6 +66,7 @@ public: status_t Access(uint32* supported, uint32* allowed); status_t Close(); + status_t Create(); status_t GetAttr(AttrValue** attrs, uint32* count); status_t GetFH(Filehandle* fh); status_t Link(); diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp index 4ce72edc8e..e45eafb6b8 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp @@ -86,6 +86,33 @@ RequestBuilder::Close(uint32 seq, const uint32* id, uint32 stateSeq) } +status_t +RequestBuilder::Create(FileType type, const char* name, const char* path, + AttrValue* attr, uint32 count) +{ + if (fProcedure != ProcCompound) + return B_BAD_VALUE; + if (fRequest == NULL) + return B_NO_MEMORY; + if (path == NULL) + return B_BAD_VALUE; + if (name == NULL) + return B_BAD_VALUE; + if (type != NF4LNK) + return B_BAD_VALUE; + + fRequest->Stream().AddUInt(OpCreate); + fRequest->Stream().AddUInt(type); + fRequest->Stream().AddString(path); + fRequest->Stream().AddString(name); + _EncodeAttrs(fRequest->Stream(), attr, count); + + fOpCount++; + + return B_OK; +} + + status_t RequestBuilder::GetAttr(Attribute* attrs, uint32 count) { @@ -459,22 +486,8 @@ RequestBuilder::Verify(AttrValue* attr, uint32 count) return B_NO_MEMORY; fRequest->Stream().AddUInt(OpVerify); + _EncodeAttrs(fRequest->Stream(), attr, count); - Attribute* attrs = - reinterpret_cast(malloc(sizeof(Attribute) * count)); - for (uint32 i = 0; i < count; i++) - attrs[i] = static_cast(attr[i].fAttribute); - _AttrBitmap(fRequest->Stream(), attrs, count); - free(attrs); - - uint32 i = 0; - XDR::WriteStream str; - if (i < count && attr[i].fAttribute == FATTR4_TYPE) { - str.AddUInt(attr[i].fData.fValue32); - i++; - } - - fRequest->Stream().AddOpaque(str); fOpCount++; return B_OK; @@ -511,3 +524,30 @@ RequestBuilder::_AttrBitmap(XDR::WriteStream& stream, Attribute* attrs, stream.AddUInt(bitmap[i]); } + +void +RequestBuilder::_EncodeAttrs(XDR::WriteStream& stream, AttrValue* attr, + uint32 count) +{ + Attribute* attrs = + reinterpret_cast(malloc(sizeof(Attribute) * count)); + for (uint32 i = 0; i < count; i++) + attrs[i] = static_cast(attr[i].fAttribute); + _AttrBitmap(stream, attrs, count); + free(attrs); + + uint32 i = 0; + XDR::WriteStream str; + if (i < count && attr[i].fAttribute == FATTR4_TYPE) { + str.AddUInt(attr[i].fData.fValue32); + i++; + } + + if (i < count && attr[i].fAttribute == FATTR4_MODE) { + str.AddUInt(attr[i].fData.fValue32); + i++; + } + + stream.AddOpaque(str); +} + diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h index 9710cf171e..8101cd4059 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h @@ -28,6 +28,9 @@ public: status_t Access(); status_t Close(uint32 seq, const uint32* id, uint32 stateSeq); + status_t Create(FileType type, const char* name, + const char* path, AttrValue* attr, + uint32 count); status_t GetAttr(Attribute* attrs, uint32 count); status_t GetFH(); status_t Link(const char* name); @@ -59,6 +62,8 @@ public: private: void _InitHeader(); + void _EncodeAttrs(XDR::WriteStream& stream, + AttrValue* attr, uint32 count); void _AttrBitmap(XDR::WriteStream& stream, Attribute* attrs, uint32 count); 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 e8f7b2949f..8a5781cac8 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -212,6 +212,15 @@ nfs4_read_symlink(fs_volume* volume, fs_vnode* link, char* buffer, } +static status_t +nfs4_create_symlink(fs_volume* volume, fs_vnode* dir, const char* name, + const char* path, int mode) +{ + Inode* inode = reinterpret_cast(dir->private_node); + return inode->CreateLink(name, path, mode); +} + + static status_t nfs4_link(fs_volume* volume, fs_vnode* dir, const char* name, fs_vnode* vnode) { @@ -456,7 +465,7 @@ fs_vnode_ops gNFSv4VnodeOps = { NULL, // fsync() nfs4_read_symlink, - NULL, // create_symlink() + nfs4_create_symlink, nfs4_link, nfs4_unlink, From 20bd3ee165c505a6105c7ca16b707db2a479ee05 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Tue, 26 Jun 2012 16:43:37 +0200 Subject: [PATCH 072/252] 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, From e36a54427c52d685efec2862cba812ac46a15ad4 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Tue, 26 Jun 2012 17:05:05 +0200 Subject: [PATCH 073/252] nfs4: Add write() hook --- .../kernel/file_systems/nfs4/Inode.cpp | 68 +++++++++++++++++++ src/add-ons/kernel/file_systems/nfs4/Inode.h | 2 + .../kernel/file_systems/nfs4/NFS4Defs.h | 9 ++- .../file_systems/nfs4/ReplyInterpreter.cpp | 15 ++++ .../file_systems/nfs4/ReplyInterpreter.h | 1 + .../file_systems/nfs4/RequestBuilder.cpp | 24 +++++++ .../kernel/file_systems/nfs4/RequestBuilder.h | 3 + .../file_systems/nfs4/kernel_interface.cpp | 20 +++++- 8 files changed, 140 insertions(+), 2 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index ae11bb6276..847b35428d 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -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(_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) { diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h b/src/add-ons/kernel/file_systems/nfs4/Inode.h index ae649add73..7139d76ee4 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -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, diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h index 7cb8e801d2..ffa17d5975 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h @@ -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, diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp index dd03e0ef81..81359239f1 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp @@ -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) { diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h index 9c22a5e55b..e7c7a566a2 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h @@ -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(); diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp index eebbc0f20d..d4090cb01d 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp @@ -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() { diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h index e864576f7d..b6cc110d53 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h @@ -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(); 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 fd24f6fa56..220c2b7aaf 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -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(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(_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() From 636e922e5c38aab48923a27a7f8d73300b7bda62 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Tue, 26 Jun 2012 17:21:06 +0200 Subject: [PATCH 074/252] nfs4: Fix cookie and vnode creation in create() hook --- src/add-ons/kernel/file_systems/nfs4/Cookie.cpp | 2 +- src/add-ons/kernel/file_systems/nfs4/Cookie.h | 3 +-- src/add-ons/kernel/file_systems/nfs4/Inode.cpp | 9 +++++---- .../kernel/file_systems/nfs4/kernel_interface.cpp | 5 +++++ 4 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Cookie.cpp b/src/add-ons/kernel/file_systems/nfs4/Cookie.cpp index e2cc986c43..2cf9f0d9d4 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Cookie.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Cookie.cpp @@ -77,7 +77,7 @@ Cookie::CancelAll() mutex_lock(&fRequestLock); RequestEntry* ent = fRequests; while (ent != NULL) { - fInode->FileSystem()->Server()->WakeCall(ent->fRequest); + fFilesystem->Server()->WakeCall(ent->fRequest); ent = ent->fNext; } mutex_unlock(&fRequestLock); diff --git a/src/add-ons/kernel/file_systems/nfs4/Cookie.h b/src/add-ons/kernel/file_systems/nfs4/Cookie.h index 13671baee0..82fcdc4439 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Cookie.h +++ b/src/add-ons/kernel/file_systems/nfs4/Cookie.h @@ -13,7 +13,6 @@ #include "Filesystem.h" -class Inode; struct Cookie { struct RequestEntry { @@ -21,7 +20,7 @@ struct Cookie { RequestEntry* fNext; }; - Inode* fInode; + Filesystem* fFilesystem; RequestEntry* fRequests; mutex fRequestLock; diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index 847b35428d..93d60196ec 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -712,8 +712,6 @@ Inode::Create(const char* name, int mode, int perms, OpenFileCookie* cookie, bool confirm; status_t result; - cookie->fInode = this; - cookie->fHandle = fHandle; cookie->fMode = mode; cookie->fSequence = 0; @@ -811,6 +809,9 @@ Inode::Create(const char* name, int mode, int perms, OpenFileCookie* cookie, fFilesystem->InoIdMap()->AddEntry(fi, *id); + cookie->fFilesystem = fFilesystem; + cookie->fHandle = fh; + break; } while (true); @@ -829,7 +830,7 @@ Inode::Open(int mode, OpenFileCookie* cookie) bool confirm; status_t result; - cookie->fInode = this; + cookie->fFilesystem = fFilesystem; cookie->fHandle = fHandle; cookie->fMode = mode; cookie->fSequence = 0; @@ -1131,7 +1132,7 @@ Inode::OpenDir(OpenDirCookie* cookie) if (allowed & ACCESS4_READ != ACCESS4_READ) return B_PERMISSION_DENIED; - cookie->fInode = this; + cookie->fFilesystem = fFilesystem; cookie->fCookie = 0; cookie->fCookieVerf = 2; 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 220c2b7aaf..b134504eee 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -278,6 +278,11 @@ nfs4_create(fs_volume* volume, fs_vnode* dir, const char* name, int openMode, if (result != B_OK) delete cookie; + void* ptr; + result = get_vnode(volume, *_newVnodeID, &ptr); + if (result != B_OK) + delete cookie; + return result; } From 86d2cab33f5846228cb51382da46bc7185f7c676 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Tue, 26 Jun 2012 19:46:27 +0200 Subject: [PATCH 075/252] nfs4: Add support for O_APPEND mode --- .../kernel/file_systems/nfs4/Inode.cpp | 42 +++++++++++++++++-- src/add-ons/kernel/file_systems/nfs4/Inode.h | 2 +- .../file_systems/nfs4/RequestBuilder.cpp | 5 +++ .../file_systems/nfs4/kernel_interface.cpp | 2 +- 4 files changed, 46 insertions(+), 5 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index 93d60196ec..0ddafcac14 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -1022,21 +1022,39 @@ 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) + size_t *_length) { uint32 size = 0; uint32 len = 0; + uint64 fileSize; const char* buffer = reinterpret_cast(_buffer); - while (size < length) { + while (size < *_length) { do { RPC::Server* serv = fFilesystem->Server(); Request request(serv); RequestBuilder& req = request.Builder(); + 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(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); + pos + size, *_length - size); status_t result = request.Send(cookie); if (result != B_OK) @@ -1044,6 +1062,16 @@ Inode::Write(OpenFileCookie* cookie, off_t pos, const void* _buffer, ReplyInterpreter& reply = request.Reply(); + // append: race condition + if (reply.NFS4Error() == NFS4ERR_NOT_SAME) { + if (size == 0) + continue; + else { + *_length = size; + return B_OK; + } + } + // filehandle has expired if (reply.NFS4Error() == NFS4ERR_FHEXPIRED) { _LookUpFilehandle(); @@ -1074,6 +1102,12 @@ Inode::Write(OpenFileCookie* cookie, off_t pos, const void* _buffer, if (result != B_OK) return result; + 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; @@ -1084,6 +1118,8 @@ Inode::Write(OpenFileCookie* cookie, off_t pos, const void* _buffer, } while (true); } + *_length = size; + 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 7139d76ee4..a02fa2bb03 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -50,7 +50,7 @@ public: 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); + const void* buffer, size_t *_length); status_t OpenDir(OpenDirCookie* cookie); status_t ReadDir(void* buffer, uint32 size, diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp index d4090cb01d..9426e3c2ae 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp @@ -573,6 +573,11 @@ RequestBuilder::_EncodeAttrs(XDR::WriteStream& stream, AttrValue* attr, i++; } + if (i < count && attr[i].fAttribute == FATTR4_SIZE) { + str.AddUHyper(attr[i].fData.fValue64); + i++; + } + if (i < count && attr[i].fAttribute == FATTR4_MODE) { str.AddUInt(attr[i].fData.fValue32); i++; 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 b134504eee..c769d803c7 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -372,7 +372,7 @@ nfs4_write(fs_volume* volume, fs_vnode* vnode, void* _cookie, off_t pos, OpenFileCookie* cookie = reinterpret_cast(_cookie); - return inode->Write(cookie, pos, buffer, *length); + return inode->Write(cookie, pos, buffer, length); } From 38e721106d205d1c57f7f3119f669494be632e01 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Tue, 26 Jun 2012 20:16:11 +0200 Subject: [PATCH 076/252] nfs4: Add support for O_TRUNC mode --- .../kernel/file_systems/nfs4/Inode.cpp | 29 +++++++++++++++---- 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index 0ddafcac14..1ab26f39e0 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -727,13 +727,20 @@ Inode::Create(const char* name, int mode, int perms, OpenFileCookie* cookie, req.PutFH(fParentFH); - AttrValue cattr; - cattr.fAttribute = FATTR4_MODE; - cattr.fFreePointer = false; - cattr.fData.fValue32 = perms; + AttrValue cattr[2]; + 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; req.Open(CLAIM_NULL, cookie->fSequence++, sModeToAccess(mode), - cookie->fClientId, OPEN4_CREATE, cookie->fOwnerId, name, &cattr, - 1, mode & O_EXCL == O_EXCL); + cookie->fClientId, OPEN4_CREATE, cookie->fOwnerId, name, cattr, + i + 1, (mode & O_EXCL) == O_EXCL); req.GetFH(); @@ -845,6 +852,16 @@ Inode::Open(int mode, OpenFileCookie* cookie) cookie->fOwnerId = atomic_add64(&cookie->fLastOwnerId, 1); req.PutFH(fParentFH); + + 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, fName, &attr, + 1, false); + } else req.Open(CLAIM_NULL, cookie->fSequence++, sModeToAccess(mode), cookie->fClientId, OPEN4_NOCREATE, cookie->fOwnerId, fName); From 07f2e2d2b8531ac9a4ad340dcfb8ab58dc53a8d7 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Tue, 26 Jun 2012 20:41:09 +0200 Subject: [PATCH 077/252] nfs4: Put all NFS error handling code in one function --- .../kernel/file_systems/nfs4/Inode.cpp | 257 ++++-------------- src/add-ons/kernel/file_systems/nfs4/Inode.h | 5 + 2 files changed, 63 insertions(+), 199 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index 1ab26f39e0..1253a3becb 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -49,17 +49,8 @@ Inode::CreateInode(Filesystem* fs, const FileInfo &fi, Inode** _inode) ReplyInterpreter& reply = request.Reply(); - // filehandle has expired - if (reply.NFS4Error() == NFS4ERR_FHEXPIRED) { - inode->_LookUpFilehandle(); + if (inode->_HandleErrors(reply.NFS4Error(), serv)) continue; - } - - // filesystem has been moved - if (reply.NFS4Error() == NFS4ERR_MOVED) { - fs->Migrate(inode->fHandle, serv); - continue; - } result = reply.PutFH(); if (result != B_OK) @@ -139,17 +130,8 @@ Inode::LookUp(const char* name, ino_t* id) ReplyInterpreter& reply = request.Reply(); - // filehandle has expired - if (reply.NFS4Error() == NFS4ERR_FHEXPIRED) { - _LookUpFilehandle(); + if (_HandleErrors(reply.NFS4Error(), serv)) continue; - } - - // filesystem has been moved - if (reply.NFS4Error() == NFS4ERR_MOVED) { - fFilesystem->Migrate(fHandle, serv); - continue; - } result = reply.PutFH(); if (result != B_OK) @@ -288,17 +270,8 @@ Inode::Remove(const char* name, FileType type) ReplyInterpreter& reply = request.Reply(); - // filehandle has expired - if (reply.NFS4Error() == NFS4ERR_FHEXPIRED) { - _LookUpFilehandle(); + if (_HandleErrors(reply.NFS4Error(), serv)) continue; - } - - // filesystem has been moved - if (reply.NFS4Error() == NFS4ERR_MOVED) { - fFilesystem->Migrate(fHandle, serv); - continue; - } result = reply.PutFH(); if (result != B_OK) @@ -405,17 +378,8 @@ Inode::CreateLink(const char* name, const char* path, int mode) ReplyInterpreter& reply = request.Reply(); - // filehandle has expired - if (reply.NFS4Error() == NFS4ERR_FHEXPIRED) { - _LookUpFilehandle(); + if (_HandleErrors(reply.NFS4Error(), serv)) continue; - } - - // filesystem has been moved - if (reply.NFS4Error() == NFS4ERR_MOVED) { - fFilesystem->Migrate(fHandle, serv); - continue; - } result = reply.PutFH(); if (result != B_OK) @@ -446,17 +410,8 @@ Inode::ReadLink(void* buffer, size_t* length) ReplyInterpreter& reply = request.Reply(); - // filehandle has expired - if (reply.NFS4Error() == NFS4ERR_FHEXPIRED) { - _LookUpFilehandle(); + if (_HandleErrors(reply.NFS4Error(), serv)) continue; - } - - // filesystem has been moved - if (reply.NFS4Error() == NFS4ERR_MOVED) { - fFilesystem->Migrate(fHandle, serv); - continue; - } result = reply.PutFH(); if (result != B_OK) @@ -488,17 +443,8 @@ Inode::Access(int mode) ReplyInterpreter& reply = request.Reply(); - // filehandle has expired - if (reply.NFS4Error() == NFS4ERR_FHEXPIRED) { - _LookUpFilehandle(); + if (_HandleErrors(reply.NFS4Error(), serv)) continue; - } - - // filesystem has been moved - if (reply.NFS4Error() == NFS4ERR_MOVED) { - fFilesystem->Migrate(fHandle, serv); - continue; - } result = reply.PutFH(); if (result != B_OK) @@ -551,17 +497,8 @@ Inode::Stat(struct stat* st) ReplyInterpreter& reply = request.Reply(); - // filehandle has expired - if (reply.NFS4Error() == NFS4ERR_FHEXPIRED) { - _LookUpFilehandle(); + if (_HandleErrors(reply.NFS4Error(), serv)) continue; - } - - // filesystem has been moved - if (reply.NFS4Error() == NFS4ERR_MOVED) { - fFilesystem->Migrate(fHandle, serv); - continue; - } result = reply.PutFH(); if (result != B_OK) @@ -753,25 +690,10 @@ Inode::Create(const char* name, int mode, int perms, OpenFileCookie* cookie, 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) { + if (reply.NFS4Error() == NFS4ERR_GRACE) fFilesystem->NFSServer()->ReleaseCID(cookie->fClientId); - snooze_etc(fFilesystem->NFSServer()->LeaseTime() / 3, - B_SYSTEM_TIMEBASE, B_RELATIVE_TIMEOUT); + if (_HandleErrors(reply.NFS4Error(), serv)) continue; - } result = reply.PutFH(); if (result != B_OK) @@ -871,25 +793,10 @@ Inode::Open(int mode, OpenFileCookie* cookie) 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) { + if (reply.NFS4Error() == NFS4ERR_GRACE) fFilesystem->NFSServer()->ReleaseCID(cookie->fClientId); - snooze_etc(fFilesystem->NFSServer()->LeaseTime() / 3, - B_SYSTEM_TIMEBASE, B_RELATIVE_TIMEOUT); + if (_HandleErrors(reply.NFS4Error(), serv)) continue; - } result = reply.PutFH(); if (result != B_OK) @@ -931,24 +838,8 @@ Inode::Close(OpenFileCookie* cookie) ReplyInterpreter& reply = request.Reply(); - // filehandle has expired - if (reply.NFS4Error() == NFS4ERR_FHEXPIRED) { - _LookUpFilehandle(); + if (_HandleErrors(reply.NFS4Error(), serv, cookie)) 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; - } result = reply.PutFH(); if (result != B_OK) @@ -990,31 +881,8 @@ Inode::Read(OpenFileCookie* cookie, off_t pos, void* buffer, size_t* _length) ReplyInterpreter& reply = request.Reply(); - // filehandle has expired - if (reply.NFS4Error() == NFS4ERR_FHEXPIRED) { - _LookUpFilehandle(); + if (_HandleErrors(reply.NFS4Error(), serv, cookie)) 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) @@ -1089,31 +957,8 @@ Inode::Write(OpenFileCookie* cookie, off_t pos, const void* _buffer, } } - // filehandle has expired - if (reply.NFS4Error() == NFS4ERR_FHEXPIRED) { - _LookUpFilehandle(); + if (_HandleErrors(reply.NFS4Error(), serv, cookie)) 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) @@ -1161,17 +1006,8 @@ Inode::OpenDir(OpenDirCookie* cookie) ReplyInterpreter& reply = request.Reply(); - // filehandle has expired - if (reply.NFS4Error() == NFS4ERR_FHEXPIRED) { - _LookUpFilehandle(); + if (_HandleErrors(reply.NFS4Error(), serv)) continue; - } - - // filesystem has been moved - if (reply.NFS4Error() == NFS4ERR_MOVED) { - fFilesystem->Migrate(fHandle, serv); - continue; - } result = reply.PutFH(); if (result != B_OK) @@ -1215,17 +1051,8 @@ Inode::_ReadDirOnce(DirEntry** dirents, uint32* count, OpenDirCookie* cookie, ReplyInterpreter& reply = request.Reply(); - // filehandle has expired - if (reply.NFS4Error() == NFS4ERR_FHEXPIRED) { - _LookUpFilehandle(); + if (_HandleErrors(reply.NFS4Error(), serv)) continue; - } - - // filesystem has been moved - if (reply.NFS4Error() == NFS4ERR_MOVED) { - fFilesystem->Migrate(fHandle, serv); - continue; - } result = reply.PutFH(); if (result != B_OK) @@ -1279,17 +1106,8 @@ Inode::_ReadDirUp(struct dirent* de, uint32 pos, uint32 size) ReplyInterpreter& reply = request.Reply(); - // filehandle has expired - if (reply.NFS4Error() == NFS4ERR_FHEXPIRED) { - _LookUpFilehandle(); + if (_HandleErrors(reply.NFS4Error(), serv)) continue; - } - - // filesystem has been moved - if (reply.NFS4Error() == NFS4ERR_MOVED) { - fFilesystem->Migrate(fHandle, serv); - continue; - } result = reply.PutFH(); if (result != B_OK) @@ -1408,6 +1226,47 @@ Inode::ReadDir(void* _buffer, uint32 size, uint32* _count, } +bool +Inode::_HandleErrors(uint32 nfs4Error, RPC::Server* serv, + OpenFileCookie* cookie) +{ + switch (nfs4Error) { + case NFS4_OK: + return false; + + // server needs more time, we need to wait + case NFS4ERR_DELAY: + snooze_etc(5 * 1000000, B_SYSTEM_TIMEBASE, B_RELATIVE_TIMEOUT); + return true; + + // server is in grace period, we need to wait + case NFS4ERR_GRACE: + snooze_etc(fFilesystem->NFSServer()->LeaseTime() / 3, + B_SYSTEM_TIMEBASE, B_RELATIVE_TIMEOUT); + return true; + + // 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: + _LookUpFilehandle(); + return true; + + // filesystem has been moved + case NFS4ERR_MOVED: + fFilesystem->Migrate(fHandle, serv); + return true; + + default: + return false; + } +} + + static status_t sParsePath(RequestBuilder& req, uint32* count, const char* _path) { diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h b/src/add-ons/kernel/file_systems/nfs4/Inode.h index a02fa2bb03..c1b84ec168 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -59,6 +59,11 @@ public: private: Inode(); + + bool _HandleErrors(uint32 nfs4Error, + RPC::Server* serv, + OpenFileCookie* cookie = NULL); + status_t _LookUpFilehandle(); status_t _ReadDirOnce(DirEntry** dirents, uint32* count, From e27b9ff74286c8ea666594ea0f6af5207ccca4ee Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Tue, 26 Jun 2012 20:55:53 +0200 Subject: [PATCH 078/252] nfs4: Improve handling errors in NFS replies --- .../kernel/file_systems/nfs4/Filesystem.cpp | 25 +-- .../kernel/file_systems/nfs4/Inode.cpp | 157 ++++-------------- .../kernel/file_systems/nfs4/NFS4Server.cpp | 13 +- .../file_systems/nfs4/ReplyInterpreter.cpp | 17 +- .../file_systems/nfs4/ReplyInterpreter.h | 3 + 5 files changed, 62 insertions(+), 153 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp b/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp index 3a561f05b5..55d91a1433 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp @@ -100,20 +100,13 @@ Filesystem::Mount(Filesystem** pfs, RPC::Server* serv, const char* fsPath, ReplyInterpreter& reply = request.Reply(); - result = reply.PutRootFH(); - if (result != B_OK) - return result; + reply.PutRootFH(); - for (uint32 i = 0; i < lookupCount; i++) { - result = reply.LookUp(); - if (result != B_OK) - return result; - } + for (uint32 i = 0; i < lookupCount; i++) + reply.LookUp(); Filehandle fh; - result = reply.GetFH(&fh); - if (result != B_OK) - return result; + reply.GetFH(&fh); uint32 allowed; result = reply.Access(NULL, &allowed); @@ -224,9 +217,7 @@ Filesystem::ReadInfo(struct fs_info* info) ReplyInterpreter& reply = request.Reply(); - result = reply.PutFH(); - if (result != B_OK) - return result; + reply.PutFH(); AttrValue* values; uint32 count, next = 0; @@ -301,11 +292,7 @@ Filesystem::Migrate(const Filehandle& fh, const RPC::Server* serv) ReplyInterpreter& reply = request.Reply(); - result = reply.PutFH(); - if (result != B_OK) { - mutex_unlock(&fMigrationLock); - return result; - } + reply.PutFH(); AttrValue* values; uint32 count; diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index 1253a3becb..961cfb1f77 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -52,9 +52,7 @@ Inode::CreateInode(Filesystem* fs, const FileInfo &fi, Inode** _inode) if (inode->_HandleErrors(reply.NFS4Error(), serv)) continue; - result = reply.PutFH(); - if (result != B_OK) - return result; + reply.PutFH(); AttrValue* values; uint32 count; @@ -133,21 +131,14 @@ Inode::LookUp(const char* name, ino_t* id) if (_HandleErrors(reply.NFS4Error(), serv)) continue; - result = reply.PutFH(); - if (result != B_OK) - return result; - + reply.PutFH(); if (!strcmp(name, "..")) - result = reply.LookUpUp(); + reply.LookUpUp(); else - result = reply.LookUp(); - if (result != B_OK) - return result; + reply.LookUp(); Filehandle fh; - result = reply.GetFH(&fh); - if (result != B_OK) - return result; + reply.GetFH(&fh); AttrValue* values; uint32 count; @@ -225,17 +216,9 @@ Inode::Link(Inode* dir, const char* name) continue; } - result = reply.PutFH(); - if (result != B_OK) - return result; - - result = reply.SaveFH(); - if (result != B_OK) - return result; - - result = reply.PutFH(); - if (result != B_OK) - return result; + reply.PutFH(); + reply.SaveFH(); + reply.PutFH(); return reply.Link(); } while (true); @@ -273,13 +256,8 @@ Inode::Remove(const char* name, FileType type) if (_HandleErrors(reply.NFS4Error(), serv)) continue; - result = reply.PutFH(); - if (result != B_OK) - return result; - - result = reply.LookUp(); - if (result != B_OK) - return result; + reply.PutFH(); + reply.LookUp(); result = reply.Verify(); if (result == NFS4ERR_NOT_SAME && type == NF4REG) @@ -289,10 +267,7 @@ Inode::Remove(const char* name, FileType type) if (result != B_OK) return result; - result = reply.PutFH(); - if (result != B_OK) - return result; - + reply.PutFH(); return reply.Remove(); } while (true); } @@ -338,18 +313,9 @@ Inode::Rename(Inode* from, Inode* to, const char* fromName, const char* toName) continue; } - result = reply.PutFH(); - if (result != B_OK) - return result; - - result = reply.SaveFH(); - if (result != B_OK) - return result; - - result = reply.PutFH(); - if (result != B_OK) - return result; - + reply.PutFH(); + reply.SaveFH(); + reply.PutFH(); return reply.Rename(); } while (true); @@ -381,9 +347,7 @@ Inode::CreateLink(const char* name, const char* path, int mode) if (_HandleErrors(reply.NFS4Error(), serv)) continue; - result = reply.PutFH(); - if (result != B_OK) - return result; + reply.PutFH(); return reply.Create(); } while (true); @@ -413,9 +377,7 @@ Inode::ReadLink(void* buffer, size_t* length) if (_HandleErrors(reply.NFS4Error(), serv)) continue; - result = reply.PutFH(); - if (result != B_OK) - return result; + reply.PutFH(); uint32 size; result = reply.ReadLink(buffer, &size, *length); @@ -446,9 +408,7 @@ Inode::Access(int mode) if (_HandleErrors(reply.NFS4Error(), serv)) continue; - result = reply.PutFH(); - if (result != B_OK) - return result; + reply.PutFH(); uint32 allowed; result = reply.Access(NULL, &allowed); @@ -500,9 +460,7 @@ Inode::Stat(struct stat* st) if (_HandleErrors(reply.NFS4Error(), serv)) continue; - result = reply.PutFH(); - if (result != B_OK) - return result; + reply.PutFH(); AttrValue* values; uint32 count; @@ -530,9 +488,7 @@ Inode::Stat(struct stat* st) result = request.Send(); if (result != B_OK) return result; - result = request.Reply().PutFH(); - if (result != B_OK) - return result; + request.Reply().PutFH(); uint32 prvl; result = request.Reply().Access(NULL, &prvl); if (result != B_OK) @@ -626,11 +582,7 @@ sConfirmOpen(Filesystem* fs, Filehandle& fh, OpenFileCookie* cookie) ReplyInterpreter& reply = request.Reply(); - result = reply.PutFH(); - if (result != B_OK) { - fs->NFSServer()->RemoveOpenFile(cookie); - return result; - } + reply.PutFH(); result = reply.OpenConfirm(&cookie->fStateSeq); if (result != B_OK) { @@ -695,17 +647,9 @@ Inode::Create(const char* name, int mode, int perms, OpenFileCookie* cookie, if (_HandleErrors(reply.NFS4Error(), serv)) 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; + reply.PutFH(); + reply.Open(cookie->fStateId, &cookie->fStateSeq, &confirm); + reply.GetFH(&fh); AttrValue* values; uint32 count; @@ -798,10 +742,7 @@ Inode::Open(int mode, OpenFileCookie* cookie) if (_HandleErrors(reply.NFS4Error(), serv)) continue; - result = reply.PutFH(); - if (result != B_OK) - return result; - + reply.PutFH(); result = reply.Open(cookie->fStateId, &cookie->fStateSeq, &confirm); if (result != B_OK) return result; @@ -841,10 +782,7 @@ Inode::Close(OpenFileCookie* cookie) if (_HandleErrors(reply.NFS4Error(), serv, cookie)) continue; - result = reply.PutFH(); - if (result != B_OK) - return result; - + reply.PutFH(); result = reply.Close(); if (result != B_OK) return result; @@ -884,10 +822,7 @@ Inode::Read(OpenFileCookie* cookie, off_t pos, void* buffer, size_t* _length) if (_HandleErrors(reply.NFS4Error(), serv, cookie)) continue; - result = reply.PutFH(); - if (result != B_OK) - return result; - + reply.PutFH(); result = reply.Read(reinterpret_cast(buffer) + size, &len, &eof); if (result != B_OK) @@ -960,9 +895,7 @@ Inode::Write(OpenFileCookie* cookie, off_t pos, const void* _buffer, if (_HandleErrors(reply.NFS4Error(), serv, cookie)) continue; - result = reply.PutFH(); - if (result != B_OK) - return result; + reply.PutFH(); if ((cookie->fMode & O_APPEND) == O_APPEND) { result = reply.Verify(); @@ -1009,9 +942,7 @@ Inode::OpenDir(OpenDirCookie* cookie) if (_HandleErrors(reply.NFS4Error(), serv)) continue; - result = reply.PutFH(); - if (result != B_OK) - return result; + reply.PutFH(); uint32 allowed; result = reply.Access(NULL, &allowed); @@ -1054,10 +985,7 @@ Inode::_ReadDirOnce(DirEntry** dirents, uint32* count, OpenDirCookie* cookie, if (_HandleErrors(reply.NFS4Error(), serv)) continue; - result = reply.PutFH(); - if (result != B_OK) - return result; - + reply.PutFH(); return reply.ReadDir(&cookie->fCookie, &cookie->fCookieVerf, dirents, count, eof); } while (true); @@ -1109,22 +1037,15 @@ Inode::_ReadDirUp(struct dirent* de, uint32 pos, uint32 size) if (_HandleErrors(reply.NFS4Error(), serv)) continue; - result = reply.PutFH(); - if (result != B_OK) - return result; - - result = reply.LookUpUp(); - if (result != B_OK) - return result; + reply.PutFH(); + reply.LookUpUp(); Filehandle fh; - result = reply.GetFH(&fh); - if (result != B_OK) - return result; + reply.GetFH(&fh); AttrValue* values; uint32 count; - result = reply.GetAttr(&values, &count); + reply.GetAttr(&values, &count); if (result != B_OK) return result; @@ -1314,15 +1235,9 @@ Inode::_LookUpFilehandle() ReplyInterpreter& reply = request.Reply(); - result = reply.PutRootFH(); - if (result != B_OK) - return result; - - for (uint32 i = 0; i < lookupCount; i++) { - result = reply.LookUp(); - if (result != B_OK) - return result; - } + reply.PutRootFH(); + for (uint32 i = 0; i < lookupCount; i++) + reply.LookUp(); return reply.GetFH(&fHandle); } diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp index 2a0d7b1e49..7874a949a9 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp @@ -80,9 +80,7 @@ NFS4Server::_ReclaimOpen(OpenFileCookie* cookie) ReplyInterpreter& reply = request.Reply(); - result = reply.PutFH(); - if (result != B_OK) - return result; + reply.PutFH(); bool confirm; result = reply.Open(cookie->fStateId, &cookie->fStateSeq, &confirm); @@ -100,10 +98,7 @@ NFS4Server::_ReclaimOpen(OpenFileCookie* cookie) if (result != B_OK) return result; - result = reply.PutFH(); - if (result != B_OK) - return result; - + reply.PutFH(); result = reply.OpenConfirm(&cookie->fStateSeq); if (result != B_OK) return result; @@ -203,9 +198,7 @@ NFS4Server::_GetLeaseTime() ReplyInterpreter& reply = request.Reply(); - result = reply.PutRootFH(); - if (result != B_OK) - return result; + reply.PutRootFH(); AttrValue* values; uint32 count; diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp index 81359239f1..088a50db98 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp @@ -65,6 +65,7 @@ DirEntry::~DirEntry() ReplyInterpreter::ReplyInterpreter(RPC::Reply* reply) : fNFS4Error(NFS4_OK), + fDecodeError(false), fReply(reply) { if (reply != NULL) @@ -618,16 +619,26 @@ ReplyInterpreter::_DecodeAttrs(XDR::ReadStream& str, AttrValue** attrs, status_t ReplyInterpreter::_OperationError(Opcode op) { + if (fDecodeError) + return B_BAD_VALUE; + if (fReply == NULL) return B_NOT_INITIALIZED; - if (fReply->Error() != B_OK || fReply->Stream().IsEOF()) + if (fReply->Error() != B_OK || fReply->Stream().IsEOF()) { + fDecodeError = true; return fReply->Error(); + } - if (fReply->Stream().GetInt() != op) + if (fReply->Stream().GetInt() != op) { + fDecodeError = true; return B_BAD_VALUE; + } - return _NFS4ErrorToHaiku(fReply->Stream().GetUInt()); + status_t result = _NFS4ErrorToHaiku(fReply->Stream().GetUInt()); + if (result != B_OK) + fDecodeError = true; + return result; } diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h index e7c7a566a2..3c54a28769 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h @@ -99,6 +99,7 @@ private: static status_t _NFS4ErrorToHaiku(uint32 x); uint32 fNFS4Error; + bool fDecodeError; RPC::Reply* fReply; }; @@ -109,6 +110,7 @@ ReplyInterpreter::SetTo(RPC::Reply* _reply) if (fReply != NULL) return B_DONT_DO_THAT; + fDecodeError = false; fReply = _reply; if (fReply != NULL) @@ -123,6 +125,7 @@ ReplyInterpreter::Reset() { delete fReply; fReply = NULL; + fDecodeError = false; } From 69adfb6de2fbb3d8a90071beb5576593228dc7b5 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Tue, 26 Jun 2012 21:09:30 +0200 Subject: [PATCH 079/252] nfs4: Add create_dir() hook --- .../kernel/file_systems/nfs4/Inode.cpp | 34 ++++++++++++++++++- src/add-ons/kernel/file_systems/nfs4/Inode.h | 1 + .../file_systems/nfs4/RequestBuilder.cpp | 11 +++--- .../kernel/file_systems/nfs4/RequestBuilder.h | 4 +-- .../file_systems/nfs4/kernel_interface.cpp | 11 +++++- 5 files changed, 52 insertions(+), 9 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index 961cfb1f77..e825118a4b 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -336,7 +336,7 @@ Inode::CreateLink(const char* name, const char* path, int mode) attr.fAttribute = FATTR4_MODE; attr.fFreePointer = false; attr.fData.fValue32 = mode; - req.Create(NF4LNK, name, path, &attr, 1); + req.Create(NF4LNK, name, &attr, 1, path); status_t result = request.Send(); if (result != B_OK) @@ -919,6 +919,38 @@ Inode::Write(OpenFileCookie* cookie, off_t pos, const void* _buffer, } +status_t +Inode::CreateDir(const char* name, int mode) +{ + do { + RPC::Server* serv = fFilesystem->Server(); + Request request(serv); + RequestBuilder& req = request.Builder(); + + req.PutFH(fHandle); + + AttrValue attr; + attr.fAttribute = FATTR4_MODE; + attr.fFreePointer = false; + attr.fData.fValue32 = mode; + req.Create(NF4DIR, name, &attr, 1); + + 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.Create(); + } while (true); +} + + status_t Inode::OpenDir(OpenDirCookie* cookie) { diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h b/src/add-ons/kernel/file_systems/nfs4/Inode.h index c1b84ec168..781f982faa 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -52,6 +52,7 @@ public: status_t Write(OpenFileCookie* cookie, off_t pos, const void* buffer, size_t *_length); + status_t CreateDir(const char* name, int mode); status_t OpenDir(OpenDirCookie* cookie); status_t ReadDir(void* buffer, uint32 size, uint32* count, OpenDirCookie* cookie); diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp index 9426e3c2ae..1ae16ce4c9 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp @@ -87,23 +87,24 @@ RequestBuilder::Close(uint32 seq, const uint32* id, uint32 stateSeq) status_t -RequestBuilder::Create(FileType type, const char* name, const char* path, - AttrValue* attr, uint32 count) +RequestBuilder::Create(FileType type, const char* name, AttrValue* attr, + uint32 count, const char* path) { if (fProcedure != ProcCompound) return B_BAD_VALUE; if (fRequest == NULL) return B_NO_MEMORY; - if (path == NULL) + if (type == NF4LNK && path == NULL) return B_BAD_VALUE; if (name == NULL) return B_BAD_VALUE; - if (type != NF4LNK) + if (type == NF4BLK || type == NF4CHR) return B_BAD_VALUE; fRequest->Stream().AddUInt(OpCreate); fRequest->Stream().AddUInt(type); - fRequest->Stream().AddString(path); + if (type == NF4LNK) + fRequest->Stream().AddString(path); fRequest->Stream().AddString(name); _EncodeAttrs(fRequest->Stream(), attr, count); diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h index b6cc110d53..aa1187de3c 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h @@ -29,8 +29,8 @@ public: status_t Close(uint32 seq, const uint32* id, uint32 stateSeq); status_t Create(FileType type, const char* name, - const char* path, AttrValue* attr, - uint32 count); + AttrValue* attr, uint32 count, + const char* path = NULL); status_t GetAttr(Attribute* attrs, uint32 count); status_t GetFH(); status_t Link(const char* name); 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 c769d803c7..227791eaf7 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -376,6 +376,15 @@ nfs4_write(fs_volume* volume, fs_vnode* vnode, void* _cookie, off_t pos, } +static status_t +nfs4_create_dir(fs_volume* volume, fs_vnode* parent, const char* name, + int mode) +{ + Inode* inode = reinterpret_cast(parent->private_node); + return inode->CreateDir(name, mode); +} + + static status_t nfs4_remove_dir(fs_volume* volume, fs_vnode* parent, const char* name) { @@ -526,7 +535,7 @@ fs_vnode_ops gNFSv4VnodeOps = { nfs4_write, /* directory operations */ - NULL, // create_dir() + nfs4_create_dir, nfs4_remove_dir, nfs4_open_dir, nfs4_close_dir, From 97378968277307db7d9426a6fa253e9b133823c8 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Tue, 26 Jun 2012 21:20:57 +0200 Subject: [PATCH 080/252] nfs4: Fix removing nodes other than NF4DIR or NF4REG --- src/add-ons/kernel/file_systems/nfs4/Inode.cpp | 15 +++++++++++---- src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h | 1 + .../kernel/file_systems/nfs4/ReplyInterpreter.h | 8 ++++++++ .../kernel/file_systems/nfs4/RequestBuilder.cpp | 17 +++++++++++++++++ .../kernel/file_systems/nfs4/RequestBuilder.h | 1 + 5 files changed, 38 insertions(+), 4 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index e825118a4b..f7c8b4a8d0 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -241,8 +241,11 @@ Inode::Remove(const char* name, FileType type) AttrValue attr; attr.fAttribute = FATTR4_TYPE; attr.fFreePointer = false; - attr.fData.fValue32 = type; - req.Verify(&attr, 1); + attr.fData.fValue32 = NF4DIR; + if (type == NF4DIR) + req.Verify(&attr, 1); + else + req.Nverify(&attr, 1); req.PutFH(fHandle); req.Remove(name); @@ -259,8 +262,12 @@ Inode::Remove(const char* name, FileType type) reply.PutFH(); reply.LookUp(); - result = reply.Verify(); - if (result == NFS4ERR_NOT_SAME && type == NF4REG) + if (type == NF4DIR) + result = reply.Verify(); + else + result = reply.Nverify(); + + if (result == NFS4ERR_SAME && type != NF4DIR) return B_IS_A_DIRECTORY; if (result == NFS4ERR_NOT_SAME && type == NF4DIR) return B_NOT_A_DIRECTORY; diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h index ffa17d5975..c4ebafa5d7 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h @@ -29,6 +29,7 @@ enum Opcode { OpLink = 11, OpLookUp = 15, OpLookUpUp = 16, + OpNverify = 17, OpOpen = 18, OpOpenConfirm = 20, OpPutFH = 22, diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h index 3c54a28769..89e334015e 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h @@ -72,6 +72,7 @@ public: status_t Link(); inline status_t LookUp(); inline status_t LookUpUp(); + inline status_t Nverify(); status_t Open(uint32* id, uint32* seq, bool* confirm); status_t OpenConfirm(uint32* stateSeq); inline status_t PutFH(); @@ -150,6 +151,13 @@ ReplyInterpreter::LookUpUp() } +inline status_t +ReplyInterpreter::Nverify() +{ + return _OperationError(OpNverify); +} + + inline status_t ReplyInterpreter::PutFH() { diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp index 1ae16ce4c9..aa7460e5cd 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp @@ -197,6 +197,23 @@ RequestBuilder::LookUpUp() } +status_t +RequestBuilder::Nverify(AttrValue* attr, uint32 count) +{ + if (fProcedure != ProcCompound) + return B_BAD_VALUE; + if (fRequest == NULL) + return B_NO_MEMORY; + + fRequest->Stream().AddUInt(OpNverify); + _EncodeAttrs(fRequest->Stream(), attr, count); + + fOpCount++; + + return B_OK; +} + + status_t RequestBuilder::Open(OpenClaim claim, uint32 seq, uint32 access, uint64 id, OpenCreate oc, uint64 ownerId, const char* name, AttrValue* attr, diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h index aa1187de3c..89a7379a67 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h @@ -36,6 +36,7 @@ public: status_t Link(const char* name); status_t LookUp(const char* name); status_t LookUpUp(); + status_t Nverify(AttrValue* attr, uint32 count); status_t Open(OpenClaim claim, uint32 seq, uint32 access, uint64 id, OpenCreate oc, uint64 ownerId, const char* name, From 684d0a10368ef10ce0ad68ce09ecde8ca2d4bf12 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Tue, 26 Jun 2012 21:27:11 +0200 Subject: [PATCH 081/252] nfs4: Partial handling of NFS4ERR_LEASE_MOVED error --- src/add-ons/kernel/file_systems/nfs4/Inode.cpp | 5 +++++ src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp | 1 + 2 files changed, 6 insertions(+) diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index f7c8b4a8d0..ab6c85bd0e 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -1221,6 +1221,11 @@ Inode::_HandleErrors(uint32 nfs4Error, RPC::Server* serv, fFilesystem->Migrate(fHandle, serv); return true; + // lease has been moved, provoke server to return NFS4ERR_MOVED + case NFS4ERR_LEASE_MOVED: + Access(0); + return true; + default: return false; } diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp index 7874a949a9..5a74bd94cb 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp @@ -271,6 +271,7 @@ NFS4Server::_Renewal() if (request.Reply().NFS4Error() == NFS4ERR_STALE_CLIENTID) ServerRebooted(clientId); + // TODO: support NFS4ERR_LEASE_MOVED } return B_OK; From abba2fddf17a30a2097f7e04c57b67b50f708ece Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Tue, 26 Jun 2012 23:16:23 +0200 Subject: [PATCH 082/252] nfs4: Add write_stat() hook --- .../kernel/file_systems/nfs4/Inode.cpp | 89 +++++++++++++++++++ src/add-ons/kernel/file_systems/nfs4/Inode.h | 2 + .../kernel/file_systems/nfs4/NFS4Defs.h | 1 + .../file_systems/nfs4/ReplyInterpreter.cpp | 15 ++++ .../file_systems/nfs4/ReplyInterpreter.h | 1 + .../file_systems/nfs4/RequestBuilder.cpp | 50 +++++++++++ .../kernel/file_systems/nfs4/RequestBuilder.h | 2 + .../file_systems/nfs4/kernel_interface.cpp | 11 ++- 8 files changed, 170 insertions(+), 1 deletion(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index ab6c85bd0e..ebd28e7037 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -12,6 +12,8 @@ #include #include +#include + #include "Request.h" @@ -554,6 +556,93 @@ Inode::Stat(struct stat* st) } +status_t +Inode::WriteStat(const struct stat* st, uint32 mask) +{ + status_t result; + OpenFileCookie* cookie = NULL; + AttrValue attr[4]; + uint32 i = 0; + + if ((mask & B_STAT_SIZE) != 0) { + delete cookie; + cookie = new OpenFileCookie; + if (cookie == NULL) + return B_NO_MEMORY; + + result = Open(O_WRONLY, cookie); + if (result != B_OK) { + delete cookie; + return result; + } + + attr[i].fAttribute = FATTR4_SIZE; + attr[i].fFreePointer = false; + attr[i].fData.fValue64 = st->st_size; + i++; + } + + if ((mask & B_STAT_MODE) != 0) { + attr[i].fAttribute = FATTR4_MODE; + attr[i].fFreePointer = false; + attr[i].fData.fValue32 = st->st_mode; + i++; + } + + if ((mask & B_STAT_ACCESS_TIME) != 0) { + attr[i].fAttribute = FATTR4_TIME_ACCESS_SET; + attr[i].fFreePointer = true; + attr[i].fData.fPointer = malloc(sizeof(st->st_atime)); + memcpy(attr[i].fData.fPointer, &st->st_atime, sizeof(st->st_atime)); + i++; + } + + if ((mask & B_STAT_MODIFICATION_TIME) != 0) { + attr[i].fAttribute = FATTR4_TIME_MODIFY_SET; + attr[i].fFreePointer = true; + attr[i].fData.fPointer = malloc(sizeof(st->st_mtime)); + memcpy(attr[i].fData.fPointer, &st->st_mtime, sizeof(st->st_mtime)); + i++; + } + + do { + RPC::Server* serv = fFilesystem->Server(); + Request request(serv); + RequestBuilder& req = request.Builder(); + + req.PutFH(fHandle); + if ((mask & B_STAT_SIZE) != 0) + req.SetAttr(cookie->fStateId, cookie->fStateSeq, attr, i); + else + req.SetAttr(NULL, 0, attr, i); + + status_t result = request.Send(); + if (result != B_OK) { + Close(cookie); + delete cookie; + return result; + } + + ReplyInterpreter& reply = request.Reply(); + + if (_HandleErrors(reply.NFS4Error(), serv)) + continue; + + reply.PutFH(); + result = reply.SetAttr(); + + if ((mask & B_STAT_SIZE) != 0) { + Close(cookie); + delete cookie; + } + + return result; + } while (true); + + return B_OK; +} + + static OpenAccess sModeToAccess(int mode) { diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h b/src/add-ons/kernel/file_systems/nfs4/Inode.h index 781f982faa..88fd1f9f73 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -40,8 +40,10 @@ public: status_t Remove(const char* name, FileType type); static status_t Rename(Inode* from, Inode* to, const char* fromName, const char* toName); + status_t Access(int mode); status_t Stat(struct stat* st); + status_t WriteStat(const struct stat* st, uint32 mask); status_t Create(const char* name, int mode, int perms, OpenFileCookie* cookie, ino_t* id); diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h index c4ebafa5d7..2268d56fc1 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h @@ -41,6 +41,7 @@ enum Opcode { OpRename = 29, OpRenew = 30, OpSaveFH = 32, + OpSetAttr = 34, OpSetClientID = 35, OpSetClientIDConfirm = 36, OpVerify = 37, diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp index 088a50db98..981a775da9 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp @@ -359,6 +359,21 @@ ReplyInterpreter::Rename() } +status_t +ReplyInterpreter::SetAttr() +{ + status_t res = _OperationError(OpSetAttr); + if (res != B_OK) + return res; + + uint32 bcount = fReply->Stream().GetUInt(); + for (uint32 i = 0; i < bcount; i++) + fReply->Stream().GetUInt(); + + return fReply->Stream().IsEOF() ? B_BAD_VALUE : B_OK; +} + + status_t ReplyInterpreter::SetClientID(uint64* clientid, uint64* verifier) { diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h index 89e334015e..aa504a5592 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h @@ -85,6 +85,7 @@ public: status_t Rename(); inline status_t Renew(); inline status_t SaveFH(); + status_t SetAttr(); status_t SetClientID(uint64* clientid, uint64* verifier); inline status_t SetClientIDConfirm(); inline status_t Verify(); diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp index aa7460e5cd..a3108aa8b6 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp @@ -444,6 +444,34 @@ RequestBuilder::SaveFH() } +status_t +RequestBuilder::SetAttr(const uint32* id, uint32 stateSeq, AttrValue* attr, + uint32 count) +{ + if (fProcedure != ProcCompound) + return B_BAD_VALUE; + if (fRequest == NULL) + return B_NO_MEMORY; + + fRequest->Stream().AddUInt(OpSetAttr); + fRequest->Stream().AddUInt(stateSeq); + if (id != NULL) { + fRequest->Stream().AddUInt(id[0]); + fRequest->Stream().AddUInt(id[1]); + fRequest->Stream().AddUInt(id[2]); + } else { + fRequest->Stream().AddUInt(0); + fRequest->Stream().AddUInt(0); + fRequest->Stream().AddUInt(0); + } + _EncodeAttrs(fRequest->Stream(), attr, count); + + fOpCount++; + + return B_OK; +} + + status_t RequestBuilder::SetClientID(const RPC::Server* serv) { @@ -601,6 +629,28 @@ RequestBuilder::_EncodeAttrs(XDR::WriteStream& stream, AttrValue* attr, i++; } + if (i < count && attr[i].fAttribute == FATTR4_TIME_ACCESS_SET) { + str.AddInt(1); // SET_TO_CLIENT_TIME4 + + struct timespec* ts = + reinterpret_cast(attr[i].fData.fPointer); + str.AddHyper(ts->tv_sec); + str.AddUInt(ts->tv_nsec); + + i++; + } + + if (i < count && attr[i].fAttribute == FATTR4_TIME_MODIFY_SET) { + str.AddInt(1); // SET_TO_CLIENT_TIME4 + + struct timespec* ts = + reinterpret_cast(attr[i].fData.fPointer); + str.AddHyper(ts->tv_sec); + str.AddUInt(ts->tv_nsec); + + i++; + } + stream.AddOpaque(str); } diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h index 89a7379a67..805d7005fb 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h @@ -56,6 +56,8 @@ public: status_t Rename(const char* from, const char* to); status_t Renew(uint64 clientId); status_t SaveFH(); + status_t SetAttr(const uint32* id, uint32 stateSeq, + AttrValue* attr, uint32 count); status_t SetClientID(const RPC::Server* serv); status_t SetClientIDConfirm(uint64 id, uint64 ver); status_t Verify(AttrValue* attr, uint32 count); 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 227791eaf7..dcb73c721f 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,15 @@ nfs4_read_stat(fs_volume* volume, fs_vnode* vnode, struct stat* stat) } +static status_t +nfs4_write_stat(fs_volume* volume, fs_vnode* vnode, const struct stat* stat, + uint32 statMask) +{ + Inode* inode = reinterpret_cast(vnode->private_node); + return inode->WriteStat(stat, statMask); +} + + static status_t nfs4_create(fs_volume* volume, fs_vnode* dir, const char* name, int openMode, int perms, void** _cookie, ino_t* _newVnodeID) @@ -523,7 +532,7 @@ fs_vnode_ops gNFSv4VnodeOps = { nfs4_access, nfs4_read_stat, - NULL, // write_stat() + nfs4_write_stat, NULL, // fs_preallocate() /* file operations */ From 38a1270e112ba367d35b8b38bb82c5933b417695 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Tue, 26 Jun 2012 23:23:58 +0200 Subject: [PATCH 083/252] nfs4: Wrong filehandle used when creating a file --- src/add-ons/kernel/file_systems/nfs4/Inode.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index ebd28e7037..dd3952315f 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -710,7 +710,7 @@ Inode::Create(const char* name, int mode, int perms, OpenFileCookie* cookie, cookie->fOwnerId = atomic_add64(&cookie->fLastOwnerId, 1); - req.PutFH(fParentFH); + req.PutFH(fHandle); AttrValue cattr[2]; uint32 i = 0; From 2f6ae7236d98a3400ea69b6a85b88d834a11a2a5 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Tue, 26 Jun 2012 23:52:37 +0200 Subject: [PATCH 084/252] nfs4: Read from st_*tim instead of st_*time --- src/add-ons/kernel/file_systems/nfs4/Inode.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index dd3952315f..c8ba0e483d 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -593,7 +593,7 @@ Inode::WriteStat(const struct stat* st, uint32 mask) attr[i].fAttribute = FATTR4_TIME_ACCESS_SET; attr[i].fFreePointer = true; attr[i].fData.fPointer = malloc(sizeof(st->st_atime)); - memcpy(attr[i].fData.fPointer, &st->st_atime, sizeof(st->st_atime)); + memcpy(attr[i].fData.fPointer, &st->st_atime, sizeof(st->st_atim)); i++; } @@ -601,7 +601,7 @@ Inode::WriteStat(const struct stat* st, uint32 mask) attr[i].fAttribute = FATTR4_TIME_MODIFY_SET; attr[i].fFreePointer = true; attr[i].fData.fPointer = malloc(sizeof(st->st_mtime)); - memcpy(attr[i].fData.fPointer, &st->st_mtime, sizeof(st->st_mtime)); + memcpy(attr[i].fData.fPointer, &st->st_mtime, sizeof(st->st_mtim)); i++; } From 5cf2ee51b869a4f024dc29846192ae7662326825 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Wed, 27 Jun 2012 00:49:30 +0200 Subject: [PATCH 085/252] nfs4: Remove unused entries from inode number to filehandle map --- src/add-ons/kernel/file_systems/nfs4/InodeIdMap.h | 8 ++++++++ src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp | 1 + 2 files changed, 9 insertions(+) diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeIdMap.h b/src/add-ons/kernel/file_systems/nfs4/InodeIdMap.h index 88692037d7..8da9227f85 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeIdMap.h +++ b/src/add-ons/kernel/file_systems/nfs4/InodeIdMap.h @@ -19,6 +19,7 @@ class InodeIdMap { public: inline status_t AddEntry(const FileInfo& fi, ino_t id); + inline status_t RemoveEntry(ino_t id); inline status_t GetFileInfo(FileInfo* fi, ino_t id); private: @@ -34,6 +35,13 @@ InodeIdMap::AddEntry(const FileInfo& fi, ino_t id) } +inline status_t +InodeIdMap::RemoveEntry(ino_t id) +{ + return fMap.Remove(id); +} + + inline status_t InodeIdMap::GetFileInfo(FileInfo* fi, ino_t id) { 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 dcb73c721f..f2d56bca82 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -197,6 +197,7 @@ static status_t nfs4_put_vnode(fs_volume* volume, fs_vnode* vnode, bool reenter) { Inode* inode = reinterpret_cast(vnode->private_node); + inode->FileSystem()->InoIdMap()->RemoveEntry(inode->ID()); delete inode; return B_OK; From 1c97a367c56e45ea8121ce39f1f9f1639585ac2a Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Wed, 27 Jun 2012 01:02:01 +0200 Subject: [PATCH 086/252] nfs4: Add support for O_NONBLOCK mode --- src/add-ons/kernel/file_systems/nfs4/Inode.cpp | 16 +++++++++++----- .../file_systems/nfs4/ReplyInterpreter.cpp | 4 ++++ 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index c8ba0e483d..9779993966 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -1285,14 +1285,20 @@ Inode::_HandleErrors(uint32 nfs4Error, RPC::Server* serv, // server needs more time, we need to wait case NFS4ERR_DELAY: - snooze_etc(5 * 1000000, B_SYSTEM_TIMEBASE, B_RELATIVE_TIMEOUT); - return true; + if (cookie == NULL || (cookie->fMode & O_NONBLOCK) == 0) { + snooze_etc(5 * 1000000, B_SYSTEM_TIMEBASE, B_RELATIVE_TIMEOUT); + return true; + } else + return false; // server is in grace period, we need to wait case NFS4ERR_GRACE: - snooze_etc(fFilesystem->NFSServer()->LeaseTime() / 3, - B_SYSTEM_TIMEBASE, B_RELATIVE_TIMEOUT); - return true; + if (cookie == NULL || (cookie->fMode & O_NONBLOCK) == 0) { + snooze_etc(fFilesystem->NFSServer()->LeaseTime() / 3, + B_SYSTEM_TIMEBASE, B_RELATIVE_TIMEOUT); + return true; + } else + return false; // server has rebooted, reclaim share and try again case NFS4ERR_STALE_CLIENTID: diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp index 981a775da9..6955182e85 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp @@ -674,6 +674,10 @@ ReplyInterpreter::_NFS4ErrorToHaiku(uint32 x) case NFS4ERR_INVAL: return B_BAD_VALUE; case NFS4ERR_FBIG: return B_FILE_TOO_LARGE; // ... + case NFS4ERR_DELAY: + case NFS4ERR_GRACE: + return B_WOULD_BLOCK; + // ... default: return B_ERROR; } } From 55899460db033044fd9cb4a261dc5436e8c0b4f9 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Wed, 27 Jun 2012 18:19:12 +0200 Subject: [PATCH 087/252] nfs4: Add set_flags() hook --- .../kernel/file_systems/nfs4/kernel_interface.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) 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 f2d56bca82..b4b2d77769 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -204,6 +204,15 @@ nfs4_put_vnode(fs_volume* volume, fs_vnode* vnode, bool reenter) } +static status_t +nfs4_set_flags(fs_volume* volume, fs_vnode* vnode, void* _cookie, int flags) +{ + OpenFileCookie* cookie = reinterpret_cast(_cookie); + cookie->fMode = (cookie->fMode & ~(O_APPEND | O_NONBLOCK)) | flags; + return B_OK; +} + + static status_t nfs4_read_symlink(fs_volume* volume, fs_vnode* link, char* buffer, size_t* _bufferSize) @@ -519,7 +528,7 @@ fs_vnode_ops gNFSv4VnodeOps = { NULL, // get_file_map() NULL, // ioctl() - NULL, + nfs4_set_flags, NULL, // fs_select() NULL, // fs_deselect() NULL, // fsync() From d764d148b10b8b0f84bbf344ccc9cf35fdb2c99d Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Wed, 27 Jun 2012 18:36:07 +0200 Subject: [PATCH 088/252] Allow file systems to manage file locks Haiku implements file locking at vfs level. That would not work for remote and shared file systems, since they need to negotiate locks with peers. This patch introduces three additional hooks in fs_interface that allow file system module to take over the management of file locks. --- headers/os/drivers/fs_interface.h | 8 ++++++++ src/system/kernel/fs/vfs.cpp | 26 +++++++++++++++++++++----- 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/headers/os/drivers/fs_interface.h b/headers/os/drivers/fs_interface.h index 03d867b131..1b3f0be8f7 100644 --- a/headers/os/drivers/fs_interface.h +++ b/headers/os/drivers/fs_interface.h @@ -242,6 +242,14 @@ struct fs_vnode_ops { fs_vnode* _superVnode, ino_t* _nodeID); status_t (*get_super_vnode)(fs_volume* volume, fs_vnode* vnode, fs_volume* superVolume, fs_vnode* superVnode); + + /* lock operations */ + status_t (*test_lock)(fs_volume* volume, fs_vnode* vnode, void* cookie, + struct flock* lock); + status_t (*acquire_lock)(fs_volume* volume, fs_vnode* vnode, void* cookie, + const struct flock* lock, bool wait); + status_t (*release_lock)(fs_volume* volume, fs_vnode* vnode, void* cookie, + const struct flock* lock); }; struct file_system_module_info { diff --git a/src/system/kernel/fs/vfs.cpp b/src/system/kernel/fs/vfs.cpp index 6737a3046c..3d7628e7ca 100644 --- a/src/system/kernel/fs/vfs.cpp +++ b/src/system/kernel/fs/vfs.cpp @@ -5475,7 +5475,10 @@ file_close(struct file_descriptor* descriptor) if (status == B_OK) { // remove all outstanding locks for this team - release_advisory_lock(vnode, NULL); + if (HAS_FS_CALL(vnode, release_lock)) + status = FS_CALL(vnode, release_lock, descriptor->cookie, NULL); + else + status = release_advisory_lock(vnode, NULL); } return status; } @@ -6006,7 +6009,11 @@ common_fcntl(int fd, int op, uint32 argument, bool kernel) case F_GETLK: if (vnode != NULL) { - status = get_advisory_lock(vnode, &flock); + if (HAS_FS_CALL(vnode, test_lock)) { + status = FS_CALL(vnode, test_lock, descriptor->cookie, + &flock); + } else + status = get_advisory_lock(vnode, &flock); if (status == B_OK) { // copy back flock structure status = user_memcpy((struct flock*)argument, &flock, @@ -6025,7 +6032,11 @@ common_fcntl(int fd, int op, uint32 argument, bool kernel) if (vnode == NULL) { status = B_BAD_VALUE; } else if (flock.l_type == F_UNLCK) { - status = release_advisory_lock(vnode, &flock); + if (HAS_FS_CALL(vnode, release_lock)) { + status = FS_CALL(vnode, release_lock, descriptor->cookie, + &flock); + } else + status = release_advisory_lock(vnode, &flock); } else { // the open mode must match the lock type if (((descriptor->open_mode & O_RWMASK) == O_RDONLY @@ -6034,8 +6045,13 @@ common_fcntl(int fd, int op, uint32 argument, bool kernel) && flock.l_type == F_RDLCK)) status = B_FILE_ERROR; else { - status = acquire_advisory_lock(vnode, -1, - &flock, op == F_SETLKW); + if (HAS_FS_CALL(vnode, acquire_lock)) { + status = FS_CALL(vnode, acquire_lock, + descriptor->cookie, &flock, op == F_SETLKW); + } else { + status = acquire_advisory_lock(vnode, -1, + &flock, op == F_SETLKW); + } } } break; From 7d0b8c97865cb6a2ab1f534305913343de78ac50 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Wed, 27 Jun 2012 22:54:27 +0200 Subject: [PATCH 089/252] nfs4: Add support for file locking --- .../kernel/file_systems/nfs4/Cookie.cpp | 12 + src/add-ons/kernel/file_systems/nfs4/Cookie.h | 20 ++ .../kernel/file_systems/nfs4/Inode.cpp | 205 ++++++++++++++++++ src/add-ons/kernel/file_systems/nfs4/Inode.h | 9 + .../kernel/file_systems/nfs4/NFS4Defs.h | 38 ++++ .../kernel/file_systems/nfs4/NFS4Server.cpp | 36 ++- .../kernel/file_systems/nfs4/NFS4Server.h | 1 + .../file_systems/nfs4/ReplyInterpreter.cpp | 54 +++++ .../file_systems/nfs4/ReplyInterpreter.h | 5 + .../file_systems/nfs4/RequestBuilder.cpp | 92 ++++++++ .../kernel/file_systems/nfs4/RequestBuilder.h | 8 + .../file_systems/nfs4/kernel_interface.cpp | 62 ++++++ 12 files changed, 541 insertions(+), 1 deletion(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Cookie.cpp b/src/add-ons/kernel/file_systems/nfs4/Cookie.cpp index 2cf9f0d9d4..a539c256e8 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Cookie.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Cookie.cpp @@ -84,3 +84,15 @@ Cookie::CancelAll() return B_OK; } + +OpenFileCookie::OpenFileCookie() +{ + mutex_init(&fLocksLock, NULL); +} + + +OpenFileCookie::~OpenFileCookie() +{ + mutex_destroy(&fLocksLock); +} + diff --git a/src/add-ons/kernel/file_systems/nfs4/Cookie.h b/src/add-ons/kernel/file_systems/nfs4/Cookie.h index 82fcdc4439..c1d3b07af9 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Cookie.h +++ b/src/add-ons/kernel/file_systems/nfs4/Cookie.h @@ -14,6 +14,20 @@ #include "Filesystem.h" +struct LockInfo { + uint32 fStateId[3]; + uint32 fStateSeq; + + uint32 fSequence; + + uint32 fOwner; + uint64 fStart; + uint64 fLength; + LockType fType; + + LockInfo* fNext; +}; + struct Cookie { struct RequestEntry { RPC::Request* fRequest; @@ -46,8 +60,14 @@ struct OpenFileCookie : public Cookie { uint64 fOwnerId; static vint64 fLastOwnerId; + LockInfo* fLocks; + mutex fLocksLock; + OpenFileCookie* fNext; OpenFileCookie* fPrev; + + OpenFileCookie(); + ~OpenFileCookie(); }; struct OpenDirCookie : public Cookie { diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index 9779993966..2f589eb675 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -699,6 +699,7 @@ Inode::Create(const char* name, int mode, int perms, OpenFileCookie* cookie, cookie->fMode = mode; cookie->fSequence = 0; + cookie->fLocks = NULL; Filehandle fh; do { @@ -803,6 +804,7 @@ Inode::Open(int mode, OpenFileCookie* cookie) cookie->fHandle = fHandle; cookie->fMode = mode; cookie->fSequence = 0; + cookie->fLocks = NULL; do { cookie->fClientId = fFilesystem->NFSServer()->ClientId(); @@ -1275,6 +1277,208 @@ Inode::ReadDir(void* _buffer, uint32 size, uint32* _count, } +status_t +Inode::TestLock(OpenFileCookie* cookie, struct flock* lock) +{ + do { + RPC::Server* serv = fFilesystem->Server(); + Request request(serv); + RequestBuilder& req = request.Builder(); + + req.PutFH(fHandle); + req.LockT(sGetLockType(lock->l_type, false), lock->l_start, + lock->l_len, cookie); + + status_t result = request.Send(); + if (result != B_OK) + return result; + + ReplyInterpreter &reply = request.Reply(); + if (_HandleErrors(reply.NFS4Error(), serv, cookie)) + continue; + + reply.PutFH(); + LockType ltype; + uint64 pos, len; + result = reply.LockT(&pos, &len, <ype); + if (reply.NFS4Error() == NFS4ERR_DENIED) { + lock->l_type = sLockTypeToHaiku(ltype); + lock->l_start = static_cast(pos); + lock->l_len = static_cast(len); + result = B_OK; + } else if (reply.NFS4Error() == NFS4_OK) + lock->l_type = F_UNLCK; + + return result; + } while (true); + + return B_OK; +} + + +status_t +Inode::AcquireLock(OpenFileCookie* cookie, const struct flock* lock, + bool wait) +{ + LockInfo* linfo = new LockInfo; + if (linfo == NULL) + return B_NO_MEMORY; + + linfo->fSequence = 0; + linfo->fStart = lock->l_start; + if (lock->l_len == OFF_MAX) + linfo->fLength = UINT64_MAX; + else + linfo->fLength = lock->l_len; + linfo->fType = sGetLockType(lock->l_type, wait); + linfo->fOwner = find_thread(NULL); + + do { + RPC::Server* serv = fFilesystem->Server(); + Request request(serv); + RequestBuilder& req = request.Builder(); + + req.PutFH(fHandle); + req.Lock(cookie, linfo); + + status_t result = request.Send(); + if (result != B_OK) { + delete linfo; + return result; + } + + ReplyInterpreter &reply = request.Reply(); + if (wait && reply.NFS4Error() == NFS4ERR_DENIED) { + snooze_etc(5 * 1000000, B_SYSTEM_TIMEBASE, B_RELATIVE_TIMEOUT); + continue; + } + + if (_HandleErrors(reply.NFS4Error(), serv, cookie)) + continue; + + reply.PutFH(); + result = reply.Lock(linfo); + if (result != B_OK) { + delete linfo; + return result; + } + + break; + } while (true); + + mutex_lock(&cookie->fLocksLock); + linfo->fNext = cookie->fLocks; + cookie->fLocks = linfo; + mutex_unlock(&cookie->fLocksLock); + + return B_OK; +} + + +status_t +Inode::ReleaseLock(OpenFileCookie* cookie, const struct flock* lock) +{ + LockInfo* prev = NULL; + uint32 owner = find_thread(NULL); + + mutex_lock(&cookie->fLocksLock); + LockInfo* linfo = cookie->fLocks; + while (linfo != NULL) { + if (linfo->fOwner == owner && + linfo->fStart == static_cast(lock->l_start) && + (linfo->fLength == static_cast(lock->l_len) || + (linfo->fLength == UINT64_MAX && lock->l_len == OFF_MAX))) { + if (prev != NULL) + prev->fNext = linfo->fNext; + else + cookie->fLocks = linfo->fNext; + break; + } + + prev = linfo; + linfo = linfo->fNext; + } + mutex_unlock(&cookie->fLocksLock); + + if (linfo == NULL) + return B_BAD_VALUE; + + do { + RPC::Server* serv = fFilesystem->Server(); + Request request(serv); + RequestBuilder& req = request.Builder(); + + req.PutFH(fHandle); + req.LockU(linfo); + + 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.LockU(); + if (result != B_OK) + return result; + + break; + } while (true); + + delete linfo; + + return B_OK; +} + + +status_t +Inode::ReleaseAllLocks(OpenFileCookie* cookie) +{ + mutex_lock(&cookie->fLocksLock); + while (cookie->fLocks != NULL) { + do { + RPC::Server* serv = fFilesystem->Server(); + Request request(serv); + RequestBuilder& req = request.Builder(); + + req.PutFH(fHandle); + req.LockU(cookie->fLocks); + + status_t result = request.Send(); + if (result != B_OK) { + mutex_unlock(&cookie->fLocksLock); + return result; + } + + ReplyInterpreter &reply = request.Reply(); + + if (_HandleErrors(reply.NFS4Error(), serv, cookie)) + continue; + + reply.PutFH(); + result = reply.LockU(); + if (result != B_OK) { + mutex_unlock(&cookie->fLocksLock); + return result; + } + + break; + } while (true); + + LockInfo* linfo = cookie->fLocks->fNext; + delete cookie->fLocks; + cookie->fLocks = linfo; + } + mutex_unlock(&cookie->fLocksLock); + + return B_OK; +} + + + bool Inode::_HandleErrors(uint32 nfs4Error, RPC::Server* serv, OpenFileCookie* cookie) @@ -1284,6 +1488,7 @@ Inode::_HandleErrors(uint32 nfs4Error, RPC::Server* serv, return false; // server needs more time, we need to wait + case NFS4ERR_LOCKED: case NFS4ERR_DELAY: if (cookie == NULL || (cookie->fMode & O_NONBLOCK) == 0) { snooze_etc(5 * 1000000, B_SYSTEM_TIMEBASE, B_RELATIVE_TIMEOUT); diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h b/src/add-ons/kernel/file_systems/nfs4/Inode.h index 88fd1f9f73..1cf1f11dce 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -59,6 +59,15 @@ public: status_t ReadDir(void* buffer, uint32 size, uint32* count, OpenDirCookie* cookie); + status_t TestLock(OpenFileCookie* cookie, + struct flock* lock); + status_t AcquireLock(OpenFileCookie* cookie, + const struct flock* lock, bool wait); + status_t ReleaseLock(OpenFileCookie* cookie, + const struct flock* lock); + status_t ReleaseAllLocks(OpenFileCookie* cookie); + + private: Inode(); diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h index 2268d56fc1..11cb1f8abc 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h @@ -9,6 +9,7 @@ #define NFS4DEFS_H +#include #include #include @@ -27,6 +28,9 @@ enum Opcode { OpGetAttr = 9, OpGetFH = 10, OpLink = 11, + OpLock = 12, + OpLockT = 13, + OpLockU = 14, OpLookUp = 15, OpLookUpUp = 16, OpNverify = 17, @@ -180,6 +184,40 @@ enum WriteStable { FILE_SYNC4 = 2 }; +enum LockType { + READ_LT = 1, + WRITE_LT = 2, + READW_LT = 3, + WRITEW_LT = 4 +}; + + +static inline +LockType sGetLockType(short type, bool wait) { + switch (type) { + case F_RDLCK: return wait ? READW_LT : READ_LT; + case F_WRLCK: return wait ? WRITEW_LT : WRITE_LT; + default: return READ_LT; + } +} + + +static inline +short sLockTypeToHaiku(LockType type) { + switch (type) { + case READ_LT: + case READW_LT: + return F_RDLCK; + + case WRITE_LT: + case WRITEW_LT: + return F_WRLCK; + + default: return F_UNLCK; + } +} + + enum Errors { NFS4_OK = 0, NFS4ERR_PERM = 1, diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp index 5a74bd94cb..f8689842db 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp @@ -51,6 +51,7 @@ NFS4Server::ServerRebooted(uint64 clientId) OpenFileCookie* current = fOpenFiles; while (current != NULL) { _ReclaimOpen(current); + _ReclaimLocks(current); current = current->fNext; } mutex_unlock(&fOpenLock); @@ -74,7 +75,7 @@ NFS4Server::_ReclaimOpen(OpenFileCookie* cookie) req.Open(CLAIM_PREVIOUS, cookie->fSequence++, OPEN4_SHARE_ACCESS_READ, cookie->fClientId, OPEN4_NOCREATE, cookie->fOwnerId, NULL); - status_t result = request.Send();; + status_t result = request.Send(); if (result != B_OK) return result; @@ -108,6 +109,39 @@ NFS4Server::_ReclaimOpen(OpenFileCookie* cookie) } +status_t +NFS4Server::_ReclaimLocks(OpenFileCookie* cookie) +{ + mutex_lock(&cookie->fLocksLock); + LockInfo* linfo = cookie->fLocks; + while (linfo != NULL) { + do { + Request request(fServer); + RequestBuilder& req = request.Builder(); + + req.PutFH(cookie->fHandle); + req.Lock(cookie, linfo, true); + + status_t result = request.Send(); + if (result != B_OK) + break; + + ReplyInterpreter &reply = request.Reply(); + + reply.PutFH(); + reply.Lock(linfo); + + break; + } while (true); + + linfo = linfo->fNext; + } + mutex_unlock(&cookie->fLocksLock); + + return B_OK; +} + + void NFS4Server::AddOpenFile(OpenFileCookie* cookie) { diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h index ebe83d2ade..264e34af3e 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h @@ -31,6 +31,7 @@ public: inline uint32 LeaseTime(); private: status_t _ReclaimOpen(OpenFileCookie* cookie); + status_t _ReclaimLocks(OpenFileCookie* cookie); status_t _GetLeaseTime(); diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp index 6955182e85..dadabcb779 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp @@ -13,6 +13,8 @@ #include +#include "Cookie.h" + FSLocation::~FSLocation() { @@ -208,6 +210,56 @@ ReplyInterpreter::Link() } +status_t +ReplyInterpreter::Lock(LockInfo* linfo) +{ + status_t res = _OperationError(OpLock); + if (res != B_OK) + return res; + + linfo->fStateSeq = fReply->Stream().GetUInt(); + linfo->fStateId[0] = fReply->Stream().GetUInt(); + linfo->fStateId[1] = fReply->Stream().GetUInt(); + linfo->fStateId[2] = fReply->Stream().GetUInt(); + + return fReply->Stream().IsEOF() ? B_BAD_VALUE : B_OK; +} + + +status_t +ReplyInterpreter::LockT(uint64* pos, uint64* len, LockType* type) +{ + status_t res = _OperationError(OpLockU); + if (res != B_WOULD_BLOCK || NFS4Error() != NFS4ERR_DENIED) + return res; + + *pos = fReply->Stream().GetUHyper(); + *len = fReply->Stream().GetUHyper(); + *type = static_cast(fReply->Stream().GetInt()); + + fReply->Stream().GetUHyper(); + fReply->Stream().GetOpaque(NULL); + + return fReply->Stream().IsEOF() ? B_BAD_VALUE : B_OK; +} + + +status_t +ReplyInterpreter::LockU() +{ + status_t res = _OperationError(OpLockU); + if (res != B_OK) + return res; + + fReply->Stream().GetUInt(); + fReply->Stream().GetUInt(); + fReply->Stream().GetUInt(); + fReply->Stream().GetUInt(); + + return fReply->Stream().IsEOF() ? B_BAD_VALUE : B_OK; +} + + status_t ReplyInterpreter::Open(uint32* id, uint32* seq, bool* confirm) { @@ -675,6 +727,8 @@ ReplyInterpreter::_NFS4ErrorToHaiku(uint32 x) case NFS4ERR_FBIG: return B_FILE_TOO_LARGE; // ... case NFS4ERR_DELAY: + case NFS4ERR_DENIED: + case NFS4ERR_LOCKED: case NFS4ERR_GRACE: return B_WOULD_BLOCK; // ... diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h index aa504a5592..b96499f995 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h @@ -54,6 +54,8 @@ struct DirEntry { ~DirEntry(); }; +class LockInfo; + class ReplyInterpreter { public: ReplyInterpreter(RPC::Reply* reply = NULL); @@ -70,6 +72,9 @@ public: status_t GetAttr(AttrValue** attrs, uint32* count); status_t GetFH(Filehandle* fh); status_t Link(); + status_t Lock(LockInfo* linfo); + status_t LockT(uint64* pos, uint64* len, LockType* type); + status_t LockU(); inline status_t LookUp(); inline status_t LookUpUp(); inline status_t Nverify(); diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp index a3108aa8b6..9fd61fb8bf 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp @@ -11,6 +11,8 @@ #include +#include "Cookie.h" + RequestBuilder::RequestBuilder(Procedure proc) : @@ -146,6 +148,96 @@ RequestBuilder::GetFH() } +status_t +RequestBuilder::Lock(OpenFileCookie* cookie, LockInfo* lock, bool reclaim) +{ + if (fProcedure != ProcCompound) + return B_BAD_VALUE; + if (fRequest == NULL) + return B_NO_MEMORY; + + fRequest->Stream().AddUInt(OpLock); + + fRequest->Stream().AddInt(lock->fType); + fRequest->Stream().AddBoolean(reclaim); + + fRequest->Stream().AddUHyper(lock->fStart); + fRequest->Stream().AddUHyper(lock->fLength); + + fRequest->Stream().AddBoolean(true); // new lock owner + + // open seq stateid + fRequest->Stream().AddUInt(cookie->fSequence++); + fRequest->Stream().AddUInt(cookie->fStateSeq); + fRequest->Stream().AddUInt(cookie->fStateId[0]); + fRequest->Stream().AddUInt(cookie->fStateId[1]); + fRequest->Stream().AddUInt(cookie->fStateId[2]); + + // lock seq owner + fRequest->Stream().AddUInt(lock->fSequence++); + fRequest->Stream().AddUHyper(cookie->fClientId); + fRequest->Stream().AddOpaque(&lock->fOwner, sizeof(lock->fOwner)); + + fOpCount++; + + return B_OK; +} + + +status_t +RequestBuilder::LockT(LockType type, uint64 pos, uint64 len, + OpenFileCookie* cookie) +{ + if (fProcedure != ProcCompound) + return B_BAD_VALUE; + if (fRequest == NULL) + return B_NO_MEMORY; + + fRequest->Stream().AddUInt(OpLockT); + + fRequest->Stream().AddInt(type); + + fRequest->Stream().AddUHyper(pos); + fRequest->Stream().AddUHyper(len); + + fRequest->Stream().AddUHyper(cookie->fClientId); + + uint32 owner = find_thread(NULL); + fRequest->Stream().AddOpaque(&owner, sizeof(owner)); + + fOpCount++; + + return B_OK; +} + + +status_t +RequestBuilder::LockU(LockInfo* lock) +{ + if (fProcedure != ProcCompound) + return B_BAD_VALUE; + if (fRequest == NULL) + return B_NO_MEMORY; + + fRequest->Stream().AddUInt(OpLockU); + + fRequest->Stream().AddInt(lock->fType); + + fRequest->Stream().AddUInt(lock->fSequence++); + fRequest->Stream().AddUInt(lock->fStateSeq); + fRequest->Stream().AddUInt(lock->fStateId[0]); + fRequest->Stream().AddUInt(lock->fStateId[1]); + fRequest->Stream().AddUInt(lock->fStateId[2]); + + fRequest->Stream().AddUHyper(lock->fStart); + fRequest->Stream().AddUHyper(lock->fLength); + + fOpCount++; + + return B_OK; +} + + status_t RequestBuilder::Link(const char* name) { diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h index 805d7005fb..68dbb418f1 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h @@ -18,6 +18,9 @@ #include "XDR.h" +class OpenFileCookie; +class LockInfo; + class RequestBuilder { public: RequestBuilder(Procedure p = ProcCompound); @@ -34,6 +37,11 @@ public: status_t GetAttr(Attribute* attrs, uint32 count); status_t GetFH(); status_t Link(const char* name); + status_t Lock(OpenFileCookie* cookie, + LockInfo* lock, bool reclaim = false); + status_t LockT(LockType type, uint64 pos, + uint64 len, OpenFileCookie* cookie); + status_t LockU(LockInfo* lock); status_t LookUp(const char* name); status_t LookUpUp(); status_t Nverify(AttrValue* attr, uint32 count); 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 b4b2d77769..dc1e07e72c 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -466,6 +466,39 @@ nfs4_rewind_dir(fs_volume* volume, fs_vnode* vnode, void* _cookie) } +static status_t +nfs4_test_lock(fs_volume* volume, fs_vnode* vnode, void* _cookie, + struct flock* lock) +{ + Inode* inode = reinterpret_cast(vnode->private_node); + OpenFileCookie* cookie = reinterpret_cast(_cookie); + return inode->TestLock(cookie, lock); +} + + +static status_t +nfs4_acquire_lock(fs_volume* volume, fs_vnode* vnode, void* _cookie, + const struct flock* lock, bool wait) +{ + Inode* inode = reinterpret_cast(vnode->private_node); + OpenFileCookie* cookie = reinterpret_cast(_cookie); + return inode->AcquireLock(cookie, lock, wait); +} + + +static status_t +nfs4_release_lock(fs_volume* volume, fs_vnode* vnode, void* _cookie, + const struct flock* lock) +{ + Inode* inode = reinterpret_cast(vnode->private_node); + OpenFileCookie* cookie = reinterpret_cast(_cookie); + if (lock != NULL) + return inode->ReleaseLock(cookie, lock); + else + return inode->ReleaseAllLocks(cookie); +} + + status_t nfs4_init() { @@ -561,6 +594,35 @@ fs_vnode_ops gNFSv4VnodeOps = { nfs4_free_dir_cookie, nfs4_read_dir, nfs4_rewind_dir, + + /* attribute directory operations */ + NULL, // open_attr_dir + NULL, // close_attr_dir + NULL, // free_attr_dir_cookie + NULL, // read_attr_dir + NULL, // rewind_attr_dir + + /* attribute operations */ + NULL, // create_attr + NULL, // open_attr + NULL, // close_attr + NULL, // free_attr_cookie + NULL, // read_attr + NULL, // write_attr + + NULL, // read_attr_stat + NULL, // write_attr_stat + NULL, // rename_attr + NULL, // remove_attr + + /* support for node and FS layers */ + NULL, // create_special_node + NULL, // get_super_vnode + + /* lock operations */ + nfs4_test_lock, + nfs4_acquire_lock, + nfs4_release_lock, }; static file_system_module_info sNFSv4ModuleInfo = { From ef629eaf23e52f315956c45fffe368a244ccb379 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Wed, 27 Jun 2012 23:04:54 +0200 Subject: [PATCH 090/252] nfs4: Fix LookUp returning wrong error code if file doesn't exist --- src/add-ons/kernel/file_systems/nfs4/Inode.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index 2f589eb675..1eb880e98e 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -135,9 +135,11 @@ Inode::LookUp(const char* name, ino_t* id) reply.PutFH(); if (!strcmp(name, "..")) - reply.LookUpUp(); + result = reply.LookUpUp(); else - reply.LookUp(); + result = reply.LookUp(); + if (result != B_OK) + return result; Filehandle fh; reply.GetFH(&fh); @@ -262,7 +264,9 @@ Inode::Remove(const char* name, FileType type) continue; reply.PutFH(); - reply.LookUp(); + result = reply.LookUp(); + if (result != B_OK) + return result; if (type == NF4DIR) result = reply.Verify(); @@ -1168,7 +1172,9 @@ Inode::_ReadDirUp(struct dirent* de, uint32 pos, uint32 size) continue; reply.PutFH(); - reply.LookUpUp(); + result = reply.LookUpUp(); + if (result != B_OK) + return result; Filehandle fh; reply.GetFH(&fh); From f7bf941a8c770ed5963f1598f268fec16908827e Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Thu, 28 Jun 2012 01:07:18 +0200 Subject: [PATCH 091/252] nfs4: Verify inode number before opening a file --- .../kernel/file_systems/nfs4/Filesystem.cpp | 31 ++++++++++----- .../kernel/file_systems/nfs4/Filesystem.h | 20 ++++++++++ .../kernel/file_systems/nfs4/Inode.cpp | 39 ++++++++++++++++++- .../kernel/file_systems/nfs4/NFS4Defs.h | 11 ++++++ .../file_systems/nfs4/ReplyInterpreter.cpp | 21 +++++----- .../file_systems/nfs4/RequestBuilder.cpp | 11 ++++++ 6 files changed, 113 insertions(+), 20 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp b/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp index 55d91a1433..d3bc3549ef 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp @@ -91,7 +91,8 @@ Filesystem::Mount(Filesystem** pfs, RPC::Server* serv, const char* fsPath, req.GetFH(); req.Access(); - Attribute attr[] = { FATTR4_FSID, FATTR4_FS_LOCATIONS }; + Attribute attr[] = { FATTR4_SUPPORTED_ATTRS, FATTR4_FH_EXPIRE_TYPE, + FATTR4_FSID, FATTR4_FS_LOCATIONS }; req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); status_t result = request.Send(); @@ -119,22 +120,28 @@ Filesystem::Mount(Filesystem** pfs, RPC::Server* serv, const char* fsPath, AttrValue* values; uint32 count; result = reply.GetAttr(&values, &count); - if (result != B_OK || count < 1) + if (result != B_OK || count < 2) return result; + Filesystem* fs = new(std::nothrow) Filesystem; + if (fs == NULL) + return B_NO_MEMORY; + + // FATTR4_SUPPORTED_ATTRS is mandatory + memcpy(fs->fSupAttrs, &values[0].fData.fValue64, sizeof(fs->fSupAttrs)); + + // FATTR4_FH_EXPIRE_TYPE is mandatory + fs->fExpireType = values[1].fData.fValue32; + // FATTR4_FSID is mandatory FilesystemId* fsid = - reinterpret_cast(values[0].fData.fPointer); + reinterpret_cast(values[2].fData.fPointer); - Filesystem* fs = new(std::nothrow) Filesystem; - - if (count == 2 && values[1].fAttribute == FATTR4_FS_LOCATIONS) { + if (count == 4 && values[3].fAttribute == FATTR4_FS_LOCATIONS) { FSLocations* locs = - reinterpret_cast(values[1].fData.fLocations); + reinterpret_cast(values[3].fData.fLocations); fs->fPath = strdup(locs->fRootPath); - - delete locs; } else fs->fPath = NULL; @@ -162,6 +169,7 @@ Filesystem::Mount(Filesystem** pfs, RPC::Server* serv, const char* fsPath, *pfs = fs; + delete[] values; return B_OK; } @@ -264,6 +272,8 @@ Filesystem::ReadInfo(struct fs_info* info) info->flags = B_FS_IS_READONLY; strncpy(info->volume_name, fName, B_FILE_NAME_LENGTH); + delete[] values; + return B_OK; } @@ -310,6 +320,7 @@ Filesystem::Migrate(const Filehandle& fh, const RPC::Server* serv) reinterpret_cast(&dns)); if (result != B_OK) { mutex_unlock(&fMigrationLock); + delete[] values; return result; } @@ -337,7 +348,7 @@ Filesystem::Migrate(const Filehandle& fh, const RPC::Server* serv) } put_module(DNS_RESOLVER_MODULE_NAME); - delete locs; + delete[] values; if (server == fServer) { mutex_unlock(&fMigrationLock); diff --git a/src/add-ons/kernel/file_systems/nfs4/Filesystem.h b/src/add-ons/kernel/file_systems/nfs4/Filesystem.h index ed11fc2f89..fe50ff4766 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Filesystem.h +++ b/src/add-ons/kernel/file_systems/nfs4/Filesystem.h @@ -33,6 +33,9 @@ public: status_t Migrate(const Filehandle& fh, const RPC::Server* serv); + inline bool IsAttrSupported(Attribute attr) const; + inline uint32 ExpireType() const; + inline RPC::Server* Server(); inline NFS4Server* NFSServer(); @@ -46,6 +49,9 @@ public: private: Filesystem(); + uint32 fExpireType; + uint32 fSupAttrs[2]; + FilesystemId fFsId; const char* fPath; mutex fMigrationLock; @@ -63,6 +69,20 @@ private: }; +inline bool +Filesystem::IsAttrSupported(Attribute attr) const +{ + return sIsAttrSet(attr, fSupAttrs, 2); +} + + +inline uint32 +Filesystem::ExpireType() const +{ + return fExpireType; +} + + inline RPC::Server* Filesystem::Server() { diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index 1eb880e98e..1e18c32bca 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -819,8 +819,28 @@ Inode::Open(int mode, OpenFileCookie* cookie) cookie->fOwnerId = atomic_add64(&cookie->fLastOwnerId, 1); - req.PutFH(fParentFH); + // 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(fParentFH); + req.LookUp(fName); + AttrValue attr; + attr.fAttribute = FATTR4_FILEID; + attr.fFreePointer = false; + attr.fData.fValue64 = fFileId; + req.Verify(&attr, 1); + } else if (fFilesystem->ExpireType() == FH4_PERSISTENT) { + req.PutFH(fParentFH); + req.LookUp(fName); + AttrValue attr; + attr.fAttribute = FATTR4_FILEHANDLE; + attr.fFreePointer = true; + attr.fData.fPointer = malloc(sizeof(fHandle)); + memcpy(attr.fData.fPointer, &fHandle, sizeof(fHandle)); + req.Verify(&attr, 1); + } + req.PutFH(fParentFH); if ((mode & O_TRUNC) == O_TRUNC) { AttrValue attr; attr.fAttribute = FATTR4_SIZE; @@ -844,6 +864,21 @@ Inode::Open(int mode, OpenFileCookie* cookie) 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) @@ -1191,6 +1226,8 @@ Inode::_ReadDirUp(struct dirent* de, uint32 pos, uint32 size) } else fileId = values[0].fData.fValue64; + delete[] values; + return _FillDirEntry(de, _FileIdToInoT(fileId), "..", pos, size); } while (true); } diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h index 11cb1f8abc..5ae3b149ad 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h @@ -124,6 +124,17 @@ enum Attribute { FATTR4_MAXIMUM_ATTR_ID }; + +static inline bool sIsAttrSet(Attribute attr, const uint32* bitmap, + uint32 count) +{ + if ((uint32)attr / 32 >= count) + return false; + + return (bitmap[attr / 32] & 1 << attr % 32) != 0; +} + + enum FileType { NF4REG = 1, /* Regular File */ NF4DIR = 2, /* Directory */ diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp index dadabcb779..42ed5712bb 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp @@ -154,15 +154,6 @@ static inline uint32 sCountBits(uint32 v) } -static inline bool sIsAttrSet(Attribute attr, uint32* bitmap, uint32 count) -{ - if ((uint32)attr / 32 >= count) - return false; - - return (bitmap[attr / 32] & 1 << attr % 32) != 0; -} - - status_t ReplyInterpreter::GetAttr(AttrValue** attrs, uint32* count) { @@ -513,6 +504,18 @@ ReplyInterpreter::_DecodeAttrs(XDR::ReadStream& str, AttrValue** attrs, uint32 current = 0; + if (sIsAttrSet(FATTR4_SUPPORTED_ATTRS, bitmap, bcount)) { + values[current].fAttribute = FATTR4_SUPPORTED_ATTRS; + uint32 count = stream.GetInt(); + uint32 i; + // two uint32 are enough for NFS4, not for NFS4.1 + for (i = 0; i < min_c(count, 2); i++) + ((uint32*)&values[current].fData.fValue64)[i] = stream.GetUInt(); + for (; i < count; i++) + stream.GetUInt(); + current++; + } + if (sIsAttrSet(FATTR4_TYPE, bitmap, bcount)) { values[current].fAttribute = FATTR4_TYPE; values[current].fData.fValue32 = stream.GetInt(); diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp index 9fd61fb8bf..5654c94835 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp @@ -716,6 +716,17 @@ RequestBuilder::_EncodeAttrs(XDR::WriteStream& stream, AttrValue* attr, i++; } + if (i < count && attr[i].fAttribute == FATTR4_FILEHANDLE) { + Filehandle* fh = reinterpret_cast(attr[i].fData.fPointer); + str.AddOpaque(fh->fFH, fh->fSize); + i++; + } + + if (i < count && attr[i].fAttribute == FATTR4_FILEID) { + str.AddUHyper(attr[i].fData.fValue64); + i++; + } + if (i < count && attr[i].fAttribute == FATTR4_MODE) { str.AddUInt(attr[i].fData.fValue32); i++; From 0e1fd494e5376135714e2af0de5f1eb97b29f770 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Thu, 28 Jun 2012 01:21:48 +0200 Subject: [PATCH 092/252] nfs4: close() should also wake snoozing threads When server returns error codes like LOCKED, DEALY, etc the client waits some time before retrying (unless in O_NONBLOCK mode), close() should wake snoozing threads. --- .../kernel/file_systems/nfs4/Cookie.cpp | 7 +++++- src/add-ons/kernel/file_systems/nfs4/Cookie.h | 2 ++ .../kernel/file_systems/nfs4/Inode.cpp | 23 +++++++++++++++++-- 3 files changed, 29 insertions(+), 3 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Cookie.cpp b/src/add-ons/kernel/file_systems/nfs4/Cookie.cpp index a539c256e8..7dd4674630 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Cookie.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Cookie.cpp @@ -18,14 +18,17 @@ vint64 OpenFileCookie::fLastOwnerId = 0; Cookie::Cookie() : - fRequests(NULL) + fRequests(NULL), + fSnoozeCancel(create_sem(1, NULL)) { + acquire_sem(fSnoozeCancel); mutex_init(&fRequestLock, NULL); } Cookie::~Cookie() { + delete_sem(fSnoozeCancel); mutex_destroy(&fRequestLock); } @@ -74,6 +77,8 @@ Cookie::UnregisterRequest(RPC::Request* req) status_t Cookie::CancelAll() { + release_sem(fSnoozeCancel); + mutex_lock(&fRequestLock); RequestEntry* ent = fRequests; while (ent != NULL) { diff --git a/src/add-ons/kernel/file_systems/nfs4/Cookie.h b/src/add-ons/kernel/file_systems/nfs4/Cookie.h index c1d3b07af9..e1d9badd4b 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Cookie.h +++ b/src/add-ons/kernel/file_systems/nfs4/Cookie.h @@ -38,6 +38,8 @@ struct Cookie { RequestEntry* fRequests; mutex fRequestLock; + sem_id fSnoozeCancel; + Cookie(); virtual ~Cookie(); diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index 1e18c32bca..59c499a037 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -1533,18 +1533,37 @@ Inode::_HandleErrors(uint32 nfs4Error, RPC::Server* serv, // server needs more time, we need to wait case NFS4ERR_LOCKED: case NFS4ERR_DELAY: - if (cookie == NULL || (cookie->fMode & O_NONBLOCK) == 0) { + if (cookie == NULL) { snooze_etc(5 * 1000000, 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, 5 * 1000000); + if (result == B_TIMED_OUT) + return true; + else { + release_sem(cookie->fSnoozeCancel); + return false; + } } else return false; // server is in grace period, we need to wait case NFS4ERR_GRACE: - if (cookie == NULL || (cookie->fMode & O_NONBLOCK) == 0) { + if (cookie == NULL) { snooze_etc(fFilesystem->NFSServer()->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, + fFilesystem->NFSServer()->LeaseTime() / 3); + if (result == B_TIMED_OUT) + return true; + else { + release_sem(cookie->fSnoozeCancel); + return false; + } } else return false; From b75edefd15c76ceb9e1ccfb4195a9d3ffcfb5ff4 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Thu, 28 Jun 2012 01:38:34 +0200 Subject: [PATCH 093/252] nfs4: Add ConnectionStream and ConnectionPacket classes --- .../kernel/file_systems/nfs4/Connection.cpp | 32 +++++++++--- .../kernel/file_systems/nfs4/Connection.h | 49 +++++++------------ 2 files changed, 43 insertions(+), 38 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Connection.cpp b/src/add-ons/kernel/file_systems/nfs4/Connection.cpp index 5b455b5545..9cd6480940 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Connection.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Connection.cpp @@ -48,10 +48,9 @@ ServerAddress::operator=(const ServerAddress& x) } -Connection::Connection(const sockaddr_in& addr, Transport proto, bool markers) +Connection::Connection(const sockaddr_in& addr, Transport proto) : fSock(-1), - fUseMarkers(markers), fProtocol(proto), fServerAddress(addr) { @@ -59,6 +58,20 @@ Connection::Connection(const sockaddr_in& addr, Transport proto, bool markers) } +ConnectionStream::ConnectionStream(const sockaddr_in& addr, Transport proto) + : + Connection(addr, proto) +{ +} + + +ConnectionPacket::ConnectionPacket(const sockaddr_in& addr, Transport proto) + : + Connection(addr, proto) +{ +} + + Connection::~Connection() { if (fSock != -1) @@ -85,7 +98,7 @@ Connection::GetLocalID(ServerAddress* addr) status_t -Connection::_SendStream(const void* buffer, uint32 size) +ConnectionStream::Send(const void* buffer, uint32 size) { status_t result; @@ -120,7 +133,7 @@ Connection::_SendStream(const void* buffer, uint32 size) status_t -Connection::_SendPacket(const void* buffer, uint32 size) +ConnectionPacket::Send(const void* buffer, uint32 size) { // send on DGRAM sockets is atomic. No need to lock. status_t result = send(fSock, buffer, size, 0); @@ -132,7 +145,7 @@ Connection::_SendPacket(const void* buffer, uint32 size) status_t -Connection::_ReceiveStream(void** pbuffer, uint32* psize) +ConnectionStream::Receive(void** pbuffer, uint32* psize) { status_t result; @@ -193,7 +206,7 @@ Connection::_ReceiveStream(void** pbuffer, uint32* psize) status_t -Connection::_ReceivePacket(void** pbuffer, uint32* psize) +ConnectionPacket::Receive(void** pbuffer, uint32* psize) { status_t result; int32 size = MAX_PACKET_SIZE; @@ -231,8 +244,11 @@ Connection::Connect(Connection **pconn, const ServerAddress& id) addr.sin_addr.s_addr = htonl(id.fAddress); addr.sin_port = htons(id.fPort); - Connection* conn = new(std::nothrow) Connection(addr, id.fProtocol, - id.fProtocol == ProtocolTCP); + Connection* conn; + if (id.fProtocol == ProtocolTCP) + conn = new(std::nothrow) ConnectionStream(addr, id.fProtocol); + else + conn = new(std::nothrow) ConnectionPacket(addr, id.fProtocol); if (conn == NULL) return B_NO_MEMORY; diff --git a/src/add-ons/kernel/file_systems/nfs4/Connection.h b/src/add-ons/kernel/file_systems/nfs4/Connection.h index 6336f9e0f0..dcbb2c90e0 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Connection.h +++ b/src/add-ons/kernel/file_systems/nfs4/Connection.h @@ -35,56 +35,45 @@ class Connection { public: static status_t Connect(Connection **conn, const ServerAddress& id); - ~Connection(); + virtual ~Connection(); - inline status_t Send(const void* buffer, uint32 size); - inline status_t Receive(void** buffer, uint32* size); + virtual status_t Send(const void* buffer, uint32 size) = 0; + virtual status_t Receive(void** buffer, uint32* size) = 0; status_t GetLocalID(ServerAddress* addr); status_t Reconnect(); void Disconnect(); -private: +protected: Connection(const sockaddr_in& addr, - Transport proto, bool markers); + Transport proto); status_t _Connect(); - status_t _SendStream(const void* buffer, uint32 size); - status_t _SendPacket(const void* buffer, uint32 size); - - status_t _ReceiveStream(void** buffer, uint32* size); - status_t _ReceivePacket(void** buffer, uint32* size); - int fSock; mutex fSockLock; - const bool fUseMarkers; - const Transport fProtocol; const sockaddr_in fServerAddress; }; +class ConnectionStream : public Connection { +public: + ConnectionStream(const sockaddr_in& addr, + Transport proto); -inline status_t -Connection::Send(const void* buffer, uint32 size) -{ - if (fUseMarkers) - return _SendStream(buffer, size); - else - return _SendPacket(buffer, size); -} + virtual status_t Send(const void* buffer, uint32 size); + virtual status_t Receive(void** buffer, uint32* size); +}; +class ConnectionPacket : public Connection { +public: + ConnectionPacket(const sockaddr_in& addr, + Transport proto); -inline status_t -Connection::Receive(void** buffer, uint32* size) -{ - if (fUseMarkers) - return _ReceiveStream(buffer, size); - else - return _ReceivePacket(buffer, size); -} - + virtual status_t Send(const void* buffer, uint32 size); + virtual status_t Receive(void** buffer, uint32* size); +}; #endif // CONNECTION_H From 4318f15fa156865c22c3fc24250c582d82096975 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Thu, 28 Jun 2012 01:46:55 +0200 Subject: [PATCH 094/252] nfs4: Check for reace conditions in filehandle recovery --- .../kernel/file_systems/nfs4/Inode.cpp | 23 ++++++++++++++++--- .../file_systems/nfs4/ReplyInterpreter.cpp | 1 + 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index 59c499a037..292a71b064 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -1575,8 +1575,10 @@ Inode::_HandleErrors(uint32 nfs4Error, RPC::Server* serv, // filehandle has expired case NFS4ERR_FHEXPIRED: - _LookUpFilehandle(); - return true; + if (_LookUpFilehandle() == B_OK) + return true; + else + return false; // filesystem has been moved case NFS4ERR_MOVED: @@ -1635,6 +1637,14 @@ Inode::_LookUpFilehandle() req.GetFH(); + if (fFilesystem->IsAttrSupported(FATTR4_FILEID)) { + AttrValue attr; + attr.fAttribute = FATTR4_FILEID; + attr.fFreePointer = false; + attr.fData.fValue64 = fFileId; + req.Verify(&attr, 1); + } + status_t result = request.Send(); if (result != B_OK) return result; @@ -1645,6 +1655,13 @@ Inode::_LookUpFilehandle() for (uint32 i = 0; i < lookupCount; i++) reply.LookUp(); - return reply.GetFH(&fHandle); + result = reply.GetFH(&fHandle); + if (result != B_OK) + return result; + + if (fFilesystem->IsAttrSupported(FATTR4_FILEID)) + return reply.Verify(); + else + return B_OK; } diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp index 42ed5712bb..471b709016 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp @@ -734,6 +734,7 @@ ReplyInterpreter::_NFS4ErrorToHaiku(uint32 x) case NFS4ERR_LOCKED: case NFS4ERR_GRACE: return B_WOULD_BLOCK; + case NFS4ERR_FHEXPIRED: return B_ENTRY_NOT_FOUND; // ... default: return B_ERROR; } From b85115ddfd5c10b3e3d9d8dda6ad5b8640fcbbba Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Thu, 28 Jun 2012 01:51:24 +0200 Subject: [PATCH 095/252] nfs4: Add stub fsync() hook --- .../kernel/file_systems/nfs4/kernel_interface.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) 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 dc1e07e72c..1dd114256e 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -213,6 +213,14 @@ nfs4_set_flags(fs_volume* volume, fs_vnode* vnode, void* _cookie, int flags) } +static status_t +nfs4_fsync(fs_volume* volume, fs_vnode* vnode) +{ + // Currently, there is no cache and all writes are FILE_SYNC4 + return B_OK; +} + + static status_t nfs4_read_symlink(fs_volume* volume, fs_vnode* link, char* buffer, size_t* _bufferSize) @@ -564,7 +572,7 @@ fs_vnode_ops gNFSv4VnodeOps = { nfs4_set_flags, NULL, // fs_select() NULL, // fs_deselect() - NULL, // fsync() + nfs4_fsync, nfs4_read_symlink, nfs4_create_symlink, From 7f67d8283e8d34a7ce3ee16d27987dfe00749b7e Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Thu, 28 Jun 2012 01:55:17 +0200 Subject: [PATCH 096/252] nfs4: Add remove_vnode() hook --- .../file_systems/nfs4/kernel_interface.cpp | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) 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 1dd114256e..cec47e3710 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -204,6 +204,21 @@ nfs4_put_vnode(fs_volume* volume, fs_vnode* vnode, bool reenter) } +static status_t +nfs4_remove_vnode(fs_volume* volume, fs_vnode* vnode, bool reenter) +{ + // It is the server that actually deletes a node. Nodes on client + // side are only an attempt to simulate local filesystem. Hence, + // this hook is the same as put_vnode(). + + Inode* inode = reinterpret_cast(vnode->private_node); + inode->FileSystem()->InoIdMap()->RemoveEntry(inode->ID()); + delete inode; + + return B_OK; +} + + static status_t nfs4_set_flags(fs_volume* volume, fs_vnode* vnode, void* _cookie, int flags) { @@ -556,7 +571,7 @@ fs_vnode_ops gNFSv4VnodeOps = { nfs4_lookup, nfs4_get_vnode_name, nfs4_put_vnode, - NULL, // remove_vnode() + nfs4_remove_vnode, /* VM file access */ NULL, // can_page() From 97b7eb47f7d8baa3109902fb2b5d4000706edf50 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Thu, 28 Jun 2012 02:09:58 +0200 Subject: [PATCH 097/252] nfs4: Take advantage of supported_attrs attribute --- .../kernel/file_systems/nfs4/Inode.cpp | 54 ++++++++++--------- 1 file changed, 29 insertions(+), 25 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index 292a71b064..bf228fbb9d 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -734,8 +734,10 @@ Inode::Create(const char* name, int mode, int perms, OpenFileCookie* cookie, req.GetFH(); - Attribute attr[] = { FATTR4_FILEID }; - req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); + if (fFilesystem->IsAttrSupported(FATTR4_FILEID)) { + Attribute attr[] = { FATTR4_FILEID }; + req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); + } result = request.Send(); if (result != B_OK) @@ -752,19 +754,19 @@ Inode::Create(const char* name, int mode, int perms, OpenFileCookie* cookie, reply.Open(cookie->fStateId, &cookie->fStateSeq, &confirm); reply.GetFH(&fh); - 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) + if (fFilesystem->IsAttrSupported(FATTR4_FILEID)) { + AttrValue* values; + uint32 count; + result = reply.GetAttr(&values, &count); + if (result != B_OK) + return result; + fileId = values[1].fData.fValue64; - else + + delete[] values; + } else fileId = fFilesystem->AllocFileId(); - - delete[] values; *id = _FileIdToInoT(fileId); @@ -1194,8 +1196,11 @@ Inode::_ReadDirUp(struct dirent* de, uint32 pos, uint32 size) req.PutFH(fHandle); req.LookUpUp(); req.GetFH(); - Attribute attr[] = { FATTR4_FILEID }; - req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); + + if (fFilesystem->IsAttrSupported(FATTR4_FILEID)) { + Attribute attr[] = { FATTR4_FILEID }; + req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); + } status_t result = request.Send(); if (result != B_OK) @@ -1214,19 +1219,18 @@ Inode::_ReadDirUp(struct dirent* de, uint32 pos, uint32 size) Filehandle fh; reply.GetFH(&fh); - AttrValue* values; - uint32 count; - reply.GetAttr(&values, &count); - if (result != B_OK) - return result; - uint64 fileId; - if (count < 1 || values[0].fAttribute != FATTR4_FILEID) { - fileId = fFilesystem->AllocFileId(); - } else - fileId = values[0].fData.fValue64; + if (fFilesystem->IsAttrSupported(FATTR4_FILEID)) { + AttrValue* values; + uint32 count; + reply.GetAttr(&values, &count); + if (result != B_OK) + return result; - delete[] values; + fileId = values[0].fData.fValue64; + delete[] values; + } else + fileId = fFilesystem->AllocFileId(); return _FillDirEntry(de, _FileIdToInoT(fileId), "..", pos, size); } while (true); From e586522b518ec2fcb0212f55f3b83fb09e3516a3 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Thu, 28 Jun 2012 18:44:46 +0200 Subject: [PATCH 098/252] nfs4: Use MutexLocker for locking --- .../kernel/file_systems/nfs4/Cookie.cpp | 16 ++++------ .../kernel/file_systems/nfs4/Filesystem.cpp | 21 +++--------- .../kernel/file_systems/nfs4/Inode.cpp | 18 ++++------- .../kernel/file_systems/nfs4/InodeIdMap.h | 25 ++++++++++++++- src/add-ons/kernel/file_systems/nfs4/Jamfile | 3 +- .../kernel/file_systems/nfs4/NFS4Server.cpp | 32 +++++++------------ .../kernel/file_systems/nfs4/RPCServer.cpp | 23 ++++--------- 7 files changed, 63 insertions(+), 75 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Cookie.cpp b/src/add-ons/kernel/file_systems/nfs4/Cookie.cpp index 7dd4674630..38e6b311c5 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Cookie.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Cookie.cpp @@ -36,17 +36,15 @@ Cookie::~Cookie() status_t Cookie::RegisterRequest(RPC::Request* req) { - mutex_lock(&fRequestLock); RequestEntry* ent = new RequestEntry; - if (ent == NULL) { - mutex_unlock(&fRequestLock); + if (ent == NULL) return B_NO_MEMORY; - } + MutexLocker _(fRequestLock); ent->fRequest = req; ent->fNext = fRequests; fRequests = ent; - mutex_unlock(&fRequestLock); + return B_OK; } @@ -54,7 +52,7 @@ Cookie::RegisterRequest(RPC::Request* req) status_t Cookie::UnregisterRequest(RPC::Request* req) { - mutex_lock(&fRequestLock); + MutexLocker _(fRequestLock); RequestEntry* ent = fRequests; RequestEntry* prev = NULL; while (ent != NULL) { @@ -69,7 +67,7 @@ Cookie::UnregisterRequest(RPC::Request* req) prev = ent; ent = ent->fNext; } - mutex_unlock(&fRequestLock); + return B_OK; } @@ -79,13 +77,13 @@ Cookie::CancelAll() { release_sem(fSnoozeCancel); - mutex_lock(&fRequestLock); + MutexLocker _(fRequestLock); RequestEntry* ent = fRequests; while (ent != NULL) { fFilesystem->Server()->WakeCall(ent->fRequest); ent = ent->fNext; } - mutex_unlock(&fRequestLock); + return B_OK; } diff --git a/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp b/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp index d3bc3549ef..1d3f11f999 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp @@ -281,11 +281,9 @@ Filesystem::ReadInfo(struct fs_info* info) status_t Filesystem::Migrate(const Filehandle& fh, const RPC::Server* serv) { - mutex_lock(&fMigrationLock); - if (serv != fServer) { - mutex_unlock(&fMigrationLock); + MutexLocker _(fMigrationLock); + if (serv != fServer) return B_OK; - } Request request(fServer); RequestBuilder& req = request.Builder(); @@ -295,10 +293,8 @@ Filesystem::Migrate(const Filehandle& fh, const RPC::Server* serv) req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); status_t result = request.Send(); - if (result != B_OK) { - mutex_unlock(&fMigrationLock); + if (result != B_OK) return result; - } ReplyInterpreter& reply = request.Reply(); @@ -307,10 +303,8 @@ Filesystem::Migrate(const Filehandle& fh, const RPC::Server* serv) AttrValue* values; uint32 count; result = reply.GetAttr(&values, &count); - if (result != B_OK || count < 1) { - mutex_unlock(&fMigrationLock); + if (result != B_OK || count < 1) return result; - } FSLocations* locs = reinterpret_cast(values[0].fData.fLocations); @@ -319,7 +313,6 @@ Filesystem::Migrate(const Filehandle& fh, const RPC::Server* serv) result = get_module(DNS_RESOLVER_MODULE_NAME, reinterpret_cast(&dns)); if (result != B_OK) { - mutex_unlock(&fMigrationLock); delete[] values; return result; } @@ -350,15 +343,11 @@ Filesystem::Migrate(const Filehandle& fh, const RPC::Server* serv) put_module(DNS_RESOLVER_MODULE_NAME); delete[] values; - if (server == fServer) { - mutex_unlock(&fMigrationLock); + if (server == fServer) return B_ERROR; - } gRPCServerManager->Release(server); - mutex_unlock(&fMigrationLock); - return B_OK; } diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index bf228fbb9d..0100868ac2 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -1413,10 +1413,9 @@ Inode::AcquireLock(OpenFileCookie* cookie, const struct flock* lock, break; } while (true); - mutex_lock(&cookie->fLocksLock); + MutexLocker _(cookie->fLocksLock); linfo->fNext = cookie->fLocks; cookie->fLocks = linfo; - mutex_unlock(&cookie->fLocksLock); return B_OK; } @@ -1428,7 +1427,7 @@ Inode::ReleaseLock(OpenFileCookie* cookie, const struct flock* lock) LockInfo* prev = NULL; uint32 owner = find_thread(NULL); - mutex_lock(&cookie->fLocksLock); + MutexLocker locker(cookie->fLocksLock); LockInfo* linfo = cookie->fLocks; while (linfo != NULL) { if (linfo->fOwner == owner && @@ -1445,7 +1444,7 @@ Inode::ReleaseLock(OpenFileCookie* cookie, const struct flock* lock) prev = linfo; linfo = linfo->fNext; } - mutex_unlock(&cookie->fLocksLock); + locker.Unlock(); if (linfo == NULL) return B_BAD_VALUE; @@ -1484,7 +1483,7 @@ Inode::ReleaseLock(OpenFileCookie* cookie, const struct flock* lock) status_t Inode::ReleaseAllLocks(OpenFileCookie* cookie) { - mutex_lock(&cookie->fLocksLock); + MutexLocker _(cookie->fLocksLock); while (cookie->fLocks != NULL) { do { RPC::Server* serv = fFilesystem->Server(); @@ -1495,10 +1494,8 @@ Inode::ReleaseAllLocks(OpenFileCookie* cookie) req.LockU(cookie->fLocks); status_t result = request.Send(); - if (result != B_OK) { - mutex_unlock(&cookie->fLocksLock); + if (result != B_OK); return result; - } ReplyInterpreter &reply = request.Reply(); @@ -1507,10 +1504,8 @@ Inode::ReleaseAllLocks(OpenFileCookie* cookie) reply.PutFH(); result = reply.LockU(); - if (result != B_OK) { - mutex_unlock(&cookie->fLocksLock); + if (result != B_OK) return result; - } break; } while (true); @@ -1519,7 +1514,6 @@ Inode::ReleaseAllLocks(OpenFileCookie* cookie) delete cookie->fLocks; cookie->fLocks = linfo; } - mutex_unlock(&cookie->fLocksLock); return B_OK; } diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeIdMap.h b/src/add-ons/kernel/file_systems/nfs4/InodeIdMap.h index 8da9227f85..6cde1f39eb 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeIdMap.h +++ b/src/add-ons/kernel/file_systems/nfs4/InodeIdMap.h @@ -9,7 +9,9 @@ #define INODEIDMAP_H +#include #include +#include #include #include "Filehandle.h" @@ -17,20 +19,39 @@ class InodeIdMap { public: + inline InodeIdMap(); + inline ~InodeIdMap(); + inline status_t AddEntry(const FileInfo& fi, ino_t id); inline status_t RemoveEntry(ino_t id); inline status_t GetFileInfo(FileInfo* fi, ino_t id); private: - AVLTreeMap fMap; + AVLTreeMap fMap; + mutex fLock; }; +inline +InodeIdMap::InodeIdMap() +{ + mutex_init(&fLock, NULL); +} + + +inline +InodeIdMap::~InodeIdMap() +{ + mutex_destroy(&fLock); +} + + inline status_t InodeIdMap::AddEntry(const FileInfo& fi, ino_t id) { + MutexLocker _(fLock); return fMap.Insert(id, fi); } @@ -38,6 +59,7 @@ InodeIdMap::AddEntry(const FileInfo& fi, ino_t id) inline status_t InodeIdMap::RemoveEntry(ino_t id) { + MutexLocker _(fLock); return fMap.Remove(id); } @@ -45,6 +67,7 @@ InodeIdMap::RemoveEntry(ino_t id) inline status_t InodeIdMap::GetFileInfo(FileInfo* fi, ino_t id) { + MutexLocker _(fLock); AVLTreeMap::Iterator it = fMap.Find(id); if (!it.HasCurrent()) return B_ENTRY_NOT_FOUND; diff --git a/src/add-ons/kernel/file_systems/nfs4/Jamfile b/src/add-ons/kernel/file_systems/nfs4/Jamfile index 933b1e0112..6ee1391b40 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Jamfile +++ b/src/add-ons/kernel/file_systems/nfs4/Jamfile @@ -1,6 +1,7 @@ SubDir HAIKU_TOP src add-ons kernel file_systems nfs4 ; -UsePrivateHeaders kernel ; +UsePrivateKernelHeaders ; +UsePrivateHeaders shared ; KernelAddon nfs4 : Cookie.cpp diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp index f8689842db..9107f13c1d 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp @@ -47,14 +47,13 @@ NFS4Server::ServerRebooted(uint64 clientId) fClientId = ClientId(clientId, true); // reclaim all open files - mutex_lock(&fOpenLock); + MutexLocker _(fOpenLock); OpenFileCookie* current = fOpenFiles; while (current != NULL) { _ReclaimOpen(current); _ReclaimLocks(current); current = current->fNext; } - mutex_unlock(&fOpenLock); return fClientId; } @@ -112,7 +111,7 @@ NFS4Server::_ReclaimOpen(OpenFileCookie* cookie) status_t NFS4Server::_ReclaimLocks(OpenFileCookie* cookie) { - mutex_lock(&cookie->fLocksLock); + MutexLocker _(cookie->fLocksLock); LockInfo* linfo = cookie->fLocks; while (linfo != NULL) { do { @@ -136,7 +135,6 @@ NFS4Server::_ReclaimLocks(OpenFileCookie* cookie) linfo = linfo->fNext; } - mutex_unlock(&cookie->fLocksLock); return B_OK; } @@ -145,20 +143,19 @@ NFS4Server::_ReclaimLocks(OpenFileCookie* cookie) void NFS4Server::AddOpenFile(OpenFileCookie* cookie) { - mutex_lock(&fOpenLock); + MutexLocker _(fOpenLock); cookie->fPrev = NULL; cookie->fNext = fOpenFiles; if (fOpenFiles != NULL) fOpenFiles->fPrev = cookie; fOpenFiles = cookie; - mutex_unlock(&fOpenLock); } void NFS4Server::RemoveOpenFile(OpenFileCookie* cookie) { - mutex_lock(&fOpenLock); + MutexLocker _(fOpenLock); if (cookie == fOpenFiles) fOpenFiles = cookie->fNext; @@ -166,45 +163,42 @@ NFS4Server::RemoveOpenFile(OpenFileCookie* cookie) cookie->fNext->fPrev = cookie->fPrev; if (cookie->fPrev) cookie->fPrev->fNext = cookie->fNext; - mutex_unlock(&fOpenLock); } uint64 NFS4Server::ClientId(uint64 prevId, bool forceNew) { - mutex_lock(&fLock); + MutexLocker _(fLock); if ((forceNew && fClientId == prevId) || fCIDUseCount == 0) { Request request(fServer); request.Builder().SetClientID(fServer); status_t result = request.Send(); if (result != B_OK) - goto out_unlock; + return fClientId; uint64 ver; result = request.Reply().SetClientID(&fClientId, &ver); if (result != B_OK) - goto out_unlock; + return fClientId; request.Reset(); request.Builder().SetClientIDConfirm(fClientId, ver); result = request.Send(); if (result != B_OK) - goto out_unlock; + return fClientId; result = request.Reply().SetClientIDConfirm(); if (result != B_OK) - goto out_unlock; + return fClientId; _StartRenewing(); } fCIDUseCount++; -out_unlock: - mutex_unlock(&fLock); return fClientId; } @@ -212,9 +206,8 @@ out_unlock: void NFS4Server::ReleaseCID(uint64 cid) { - mutex_lock(&fLock); + MutexLocker _(fLock); fCIDUseCount--; - mutex_unlock(&fLock); } @@ -288,20 +281,19 @@ NFS4Server::_Renewal() // TODO: operations like OPEN, READ, CLOSE, etc also renew leases snooze_etc(fLeaseTime - 2, B_SYSTEM_TIMEBASE, B_RELATIVE_TIMEOUT | B_CAN_INTERRUPT); - mutex_lock(&fLock); + MutexLocker locker(fLock); uint64 clientId = fClientId; if (fCIDUseCount == 0) { fThreadCancel = true; - mutex_unlock(&fLock); return B_OK; } Request request(fServer); request.Builder().Renew(fClientId); request.Send(); - mutex_unlock(&fLock); + locker.Unlock(); if (request.Reply().NFS4Error() == NFS4ERR_STALE_CLIENTID) ServerRebooted(clientId); diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp b/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp index e4556d744d..3230caa172 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp @@ -11,6 +11,8 @@ #include +#include + #include "RPCReply.h" @@ -35,20 +37,19 @@ RequestManager::~RequestManager() void RequestManager::AddRequest(Request* req) { - mutex_lock(&fLock); + MutexLocker _(fLock); if (fQueueTail != NULL) fQueueTail->fNext = req; else fQueueHead = req; fQueueTail = req; - mutex_unlock(&fLock); } Request* RequestManager::FindRequest(uint32 xid) { - mutex_lock(&fLock); + MutexLocker _(fLock); Request* req = fQueueHead; Request* prev = NULL; while (req != NULL) { @@ -59,7 +60,6 @@ RequestManager::FindRequest(uint32 xid) fQueueTail = prev; if (fQueueHead == req) fQueueHead = req->fNext; - mutex_unlock(&fLock); return req; } @@ -67,7 +67,6 @@ RequestManager::FindRequest(uint32 xid) prev = req; req = req->fNext; } - mutex_unlock(&fLock); return NULL; } @@ -292,16 +291,14 @@ ServerManager::Acquire(Server** pserv, uint32 ip, uint16 port, Transport proto, id.fPort = port; id.fProtocol = proto; - mutex_lock(&fLock); + MutexLocker locker(fLock); ServerNode* node = _Find(id); if (node != NULL) { node->fRefCount++; - mutex_unlock(&fLock); - *pserv = node->fServer; + return B_OK; } - mutex_unlock(&fLock); node = new(std::nothrow) ServerNode; if (node == NULL) @@ -327,20 +324,15 @@ ServerManager::Acquire(Server** pserv, uint32 ip, uint16 port, Transport proto, node->fRefCount = 1; node->fLeft = node->fRight = NULL; - // We need to be prepared if someone already connected to the server and - // updated the BST. In such case we use that connection and cancel ours. - mutex_lock(&fLock); ServerNode* nd = _Insert(node); if (nd != node) { nd->fRefCount++; - mutex_unlock(&fLock); delete node->fServer; delete node; *pserv = nd->fServer; return B_OK; } - mutex_unlock(&fLock); *pserv = node->fServer; return B_OK; @@ -350,7 +342,7 @@ ServerManager::Acquire(Server** pserv, uint32 ip, uint16 port, Transport proto, void ServerManager::Release(Server* serv) { - mutex_lock(&fLock); + MutexLocker _(fLock); ServerNode* node = _Find(serv->ID()); if (node != NULL) { node->fRefCount--; @@ -361,7 +353,6 @@ ServerManager::Release(Server* serv) delete node; } } - mutex_unlock(&fLock); } From ecf46259e7e89e8a77cb81f0aef45a3060dd5faf Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Thu, 28 Jun 2012 18:49:19 +0200 Subject: [PATCH 099/252] nfs4: Do not release locks if cookie is NULL --- src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp | 4 ++++ 1 file changed, 4 insertions(+) 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 cec47e3710..9eee937ebd 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -514,6 +514,10 @@ nfs4_release_lock(fs_volume* volume, fs_vnode* vnode, void* _cookie, const struct flock* lock) { Inode* inode = reinterpret_cast(vnode->private_node); + + if (inode->Type() == S_IFDIR || inode->Type() == S_IFLNK) + return B_OK; + OpenFileCookie* cookie = reinterpret_cast(_cookie); if (lock != NULL) return inode->ReleaseLock(cookie, lock); From 55f2930931f8ec0739f5fcabb8942813ff891d28 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Thu, 28 Jun 2012 21:01:33 +0200 Subject: [PATCH 100/252] nfs4: Filesystem is responsible for its opened files --- .../kernel/file_systems/nfs4/Filesystem.cpp | 58 +++++++++- .../kernel/file_systems/nfs4/Filesystem.h | 20 ++++ .../kernel/file_systems/nfs4/Inode.cpp | 16 +-- .../kernel/file_systems/nfs4/NFS4Server.cpp | 102 +++++++++--------- .../kernel/file_systems/nfs4/NFS4Server.h | 38 +++++-- 5 files changed, 165 insertions(+), 69 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp b/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp index 1d3f11f999..0f07306cd6 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp @@ -9,9 +9,10 @@ #include "Filesystem.h" +#include #include -#include +#include #include #include "Request.h" @@ -24,15 +25,24 @@ extern RPC::ProgramData* CreateNFS4Server(RPC::Server* serv); Filesystem::Filesystem() : + fNext(NULL), + fPrev(NULL), + fOpenFiles(NULL), + fOpenCount(0), fPath(NULL), fName(NULL), fId(1) { + mutex_init(&fOpenLock, NULL); } Filesystem::~Filesystem() { + NFSServer()->RemoveFilesystem(this); + + mutex_destroy(&fOpenLock); + free(const_cast(fName)); free(const_cast(fPath)); } @@ -170,6 +180,8 @@ Filesystem::Mount(Filesystem** pfs, RPC::Server* serv, const char* fsPath, *pfs = fs; delete[] values; + + fs->NFSServer()->AddFilesystem(fs); return B_OK; } @@ -351,3 +363,47 @@ Filesystem::Migrate(const Filehandle& fh, const RPC::Server* serv) return B_OK; } + +OpenFileCookie* +Filesystem::OpenFilesLock() +{ + mutex_lock(&fOpenLock); + return fOpenFiles; +} + + +void +Filesystem::OpenFilesUnlock() +{ + mutex_unlock(&fOpenLock); +} + + +void +Filesystem::AddOpenFile(OpenFileCookie* cookie) +{ + MutexLocker _(fOpenLock); + + cookie->fPrev = NULL; + cookie->fNext = fOpenFiles; + if (fOpenFiles != NULL) + fOpenFiles->fPrev = cookie; + fOpenFiles = cookie; + NFSServer()->IncUsage(); +} + + +void +Filesystem::RemoveOpenFile(OpenFileCookie* cookie) +{ + MutexLocker _(fOpenLock); + if (cookie == fOpenFiles) + fOpenFiles = cookie->fNext; + + if (cookie->fNext) + cookie->fNext->fPrev = cookie->fPrev; + if (cookie->fPrev) + cookie->fPrev->fNext = cookie->fNext; + NFSServer()->DecUsage(); +} + diff --git a/src/add-ons/kernel/file_systems/nfs4/Filesystem.h b/src/add-ons/kernel/file_systems/nfs4/Filesystem.h index fe50ff4766..e115dd47ff 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Filesystem.h +++ b/src/add-ons/kernel/file_systems/nfs4/Filesystem.h @@ -33,6 +33,12 @@ public: status_t Migrate(const Filehandle& fh, const RPC::Server* serv); + OpenFileCookie* OpenFilesLock(); + void OpenFilesUnlock(); + inline uint32 OpenFilesCount(); + void AddOpenFile(OpenFileCookie* cookie); + void RemoveOpenFile(OpenFileCookie* cookie); + inline bool IsAttrSupported(Attribute attr) const; inline uint32 ExpireType() const; @@ -46,9 +52,16 @@ public: inline dev_t DevId() const; inline InodeIdMap* InoIdMap(); + + Filesystem* fNext; + Filesystem* fPrev; private: Filesystem(); + OpenFileCookie* fOpenFiles; + uint32 fOpenCount; + mutex fOpenLock; + uint32 fExpireType; uint32 fSupAttrs[2]; @@ -69,6 +82,13 @@ private: }; +inline uint32 +Filesystem::OpenFilesCount() +{ + return fOpenCount; +} + + inline bool Filesystem::IsAttrSupported(Attribute attr) const { diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index 0100868ac2..3d3a56ba44 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -676,7 +676,7 @@ sConfirmOpen(Filesystem* fs, Filehandle& fh, OpenFileCookie* cookie) status_t result = request.Send(); if (result != B_OK) { - fs->NFSServer()->RemoveOpenFile(cookie); + fs->RemoveOpenFile(cookie); return result; } @@ -686,7 +686,7 @@ sConfirmOpen(Filesystem* fs, Filehandle& fh, OpenFileCookie* cookie) result = reply.OpenConfirm(&cookie->fStateSeq); if (result != B_OK) { - fs->NFSServer()->RemoveOpenFile(cookie); + fs->RemoveOpenFile(cookie); return result; } @@ -745,8 +745,6 @@ Inode::Create(const char* name, int mode, int perms, OpenFileCookie* cookie, ReplyInterpreter& reply = request.Reply(); - if (reply.NFS4Error() == NFS4ERR_GRACE) - fFilesystem->NFSServer()->ReleaseCID(cookie->fClientId); if (_HandleErrors(reply.NFS4Error(), serv)) continue; @@ -791,7 +789,7 @@ Inode::Create(const char* name, int mode, int perms, OpenFileCookie* cookie, break; } while (true); - fFilesystem->NFSServer()->AddOpenFile(cookie); + fFilesystem->AddOpenFile(cookie); if (confirm) return sConfirmOpen(fFilesystem, fh, cookie); @@ -861,8 +859,6 @@ Inode::Open(int mode, OpenFileCookie* cookie) ReplyInterpreter& reply = request.Reply(); - if (reply.NFS4Error() == NFS4ERR_GRACE) - fFilesystem->NFSServer()->ReleaseCID(cookie->fClientId); if (_HandleErrors(reply.NFS4Error(), serv)) continue; @@ -889,7 +885,7 @@ Inode::Open(int mode, OpenFileCookie* cookie) break; } while (true); - fFilesystem->NFSServer()->AddOpenFile(cookie); + fFilesystem->AddOpenFile(cookie); if (confirm) return sConfirmOpen(fFilesystem, fHandle, cookie); @@ -901,7 +897,7 @@ Inode::Open(int mode, OpenFileCookie* cookie) status_t Inode::Close(OpenFileCookie* cookie) { - fFilesystem->NFSServer()->RemoveOpenFile(cookie); + fFilesystem->RemoveOpenFile(cookie); do { RPC::Server* serv = fFilesystem->Server(); @@ -926,8 +922,6 @@ Inode::Close(OpenFileCookie* cookie) if (result != B_OK) return result; - fFilesystem->NFSServer()->ReleaseCID(cookie->fClientId); - return B_OK; } while (true); diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp index 9107f13c1d..0d071de338 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp @@ -7,6 +7,7 @@ */ +#include "Filesystem.h" #include "Inode.h" #include "NFS4Server.h" #include "Request.h" @@ -16,25 +17,26 @@ NFS4Server::NFS4Server(RPC::Server* serv) : fThreadCancel(true), fLeaseTime(0), - fCIDUseCount(0), - fOpenFiles(NULL), + fClientIdLastUse(0), + fUseCount(0), + fFilesystems(NULL), fServer(serv) { - mutex_init(&fLock, NULL); - mutex_init(&fOpenLock, NULL); + mutex_init(&fClientIdLock, NULL); + mutex_init(&fFSLock, NULL); } NFS4Server::~NFS4Server() { fThreadCancel = true; - fCIDUseCount = 0; + fUseCount = 0; interrupt_thread(fThread); status_t result; wait_for_thread(fThread, &result); - mutex_destroy(&fLock); - mutex_destroy(&fOpenLock); + mutex_destroy(&fClientIdLock); + mutex_destroy(&fFSLock); } @@ -46,13 +48,18 @@ NFS4Server::ServerRebooted(uint64 clientId) fClientId = ClientId(clientId, true); - // reclaim all open files - MutexLocker _(fOpenLock); - OpenFileCookie* current = fOpenFiles; - while (current != NULL) { - _ReclaimOpen(current); - _ReclaimLocks(current); - current = current->fNext; + // reclaim all opened files and held locks from all filesystems + MutexLocker _(fFSLock); + Filesystem* fs = fFilesystems; + while (fs != NULL) { + OpenFileCookie* current = fs->OpenFilesLock(); + while (current != NULL) { + _ReclaimOpen(current); + _ReclaimLocks(current); + current = current->fNext; + } + fs->OpenFilesUnlock(); + fs = fs->fNext; } return fClientId; @@ -141,36 +148,42 @@ NFS4Server::_ReclaimLocks(OpenFileCookie* cookie) void -NFS4Server::AddOpenFile(OpenFileCookie* cookie) +NFS4Server::AddFilesystem(Filesystem* fs) { - MutexLocker _(fOpenLock); - cookie->fPrev = NULL; - cookie->fNext = fOpenFiles; - if (fOpenFiles != NULL) - fOpenFiles->fPrev = cookie; - fOpenFiles = cookie; + MutexLocker _(fFSLock); + fs->fPrev = NULL; + fs->fNext = fFilesystems; + if (fFilesystems != NULL) + fFilesystems->fPrev = fs; + fFilesystems = fs; + fUseCount += fs->OpenFilesCount(); + if (fs->OpenFilesCount() > 0 && fThreadCancel) + _StartRenewing(); } void -NFS4Server::RemoveOpenFile(OpenFileCookie* cookie) +NFS4Server::RemoveFilesystem(Filesystem* fs) { - MutexLocker _(fOpenLock); - if (cookie == fOpenFiles) - fOpenFiles = cookie->fNext; + MutexLocker _(fFSLock); + if (fs == fFilesystems) + fFilesystems = fs->fNext; - if (cookie->fNext) - cookie->fNext->fPrev = cookie->fPrev; - if (cookie->fPrev) - cookie->fPrev->fNext = cookie->fNext; + if (fs->fNext) + fs->fNext->fPrev = fs->fPrev; + if (fs->fPrev) + fs->fPrev->fNext = fs->fNext; + fUseCount -= fs->OpenFilesCount(); } uint64 NFS4Server::ClientId(uint64 prevId, bool forceNew) { - MutexLocker _(fLock); - if ((forceNew && fClientId == prevId) || fCIDUseCount == 0) { + MutexLocker _(fClientIdLock); + if (fClientIdLastUse + (time_t)LeaseTime() < time(NULL) + || forceNew && fClientId == prevId) { + Request request(fServer); request.Builder().SetClientID(fServer); @@ -193,24 +206,13 @@ NFS4Server::ClientId(uint64 prevId, bool forceNew) result = request.Reply().SetClientIDConfirm(); if (result != B_OK) return fClientId; - - _StartRenewing(); } - fCIDUseCount++; - + fClientIdLastUse = time(NULL); return fClientId; } -void -NFS4Server::ReleaseCID(uint64 cid) -{ - MutexLocker _(fLock); - fCIDUseCount--; -} - - status_t NFS4Server::_GetLeaseTime() { @@ -233,7 +235,7 @@ NFS4Server::_GetLeaseTime() if (result != B_OK) return result; - // FATTR4_LEASE_TIM is mandatory + // FATTR4_LEASE_TIME is mandatory if (count < 1 || values[0].fAttribute != FATTR4_LEASE_TIME) { delete[] values; return B_BAD_VALUE; @@ -251,7 +253,6 @@ NFS4Server::_StartRenewing() if (!fThreadCancel) return B_OK; - if (fLeaseTime == 0) { status_t result = _GetLeaseTime(); if (result != B_OK) @@ -281,19 +282,20 @@ NFS4Server::_Renewal() // TODO: operations like OPEN, READ, CLOSE, etc also renew leases snooze_etc(fLeaseTime - 2, B_SYSTEM_TIMEBASE, B_RELATIVE_TIMEOUT | B_CAN_INTERRUPT); - MutexLocker locker(fLock); uint64 clientId = fClientId; - if (fCIDUseCount == 0) { - fThreadCancel = true; - return B_OK; + if (fUseCount == 0) { + MutexLocker _(fFSLock); + if (fUseCount == 0) { + fThreadCancel = true; + return B_OK; + } } Request request(fServer); request.Builder().Renew(fClientId); request.Send(); - locker.Unlock(); if (request.Reply().NFS4Error() == NFS4ERR_STALE_CLIENTID) ServerRebooted(clientId); diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h index 264e34af3e..a13f642584 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h @@ -14,6 +14,7 @@ #include "RPCServer.h" +class Filesystem; class OpenFileCookie; class NFS4Server : public RPC::ProgramData { @@ -22,11 +23,14 @@ public: virtual ~NFS4Server(); uint64 ServerRebooted(uint64 clientId); - void AddOpenFile(OpenFileCookie* cookie); - void RemoveOpenFile(OpenFileCookie* cookie); + + void AddFilesystem(Filesystem* fs); + void RemoveFilesystem(Filesystem* fs); + + inline void IncUsage(); + inline void DecUsage(); uint64 ClientId(uint64 prevId = 0, bool forceNew = false); - void ReleaseCID(uint64 cid); inline uint32 LeaseTime(); private: @@ -44,16 +48,36 @@ private: uint32 fLeaseTime; uint64 fClientId; - uint32 fCIDUseCount; - mutex fLock; + bool fClientIdInit; + time_t fClientIdLastUse; + mutex fClientIdLock; - OpenFileCookie* fOpenFiles; - mutex fOpenLock; + uint32 fUseCount; + Filesystem* fFilesystems; + mutex fFSLock; RPC::Server* fServer; }; +inline void +NFS4Server::IncUsage() +{ + MutexLocker _(fFSLock); + fUseCount++; + if (fThreadCancel) + _StartRenewing(); +} + + +inline void +NFS4Server::DecUsage() +{ + MutexLocker _(fFSLock); + fUseCount--; +} + + inline uint32 NFS4Server::LeaseTime() { From 6ebe67d0d0a4157361f598e2890324c0713826d3 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Thu, 28 Jun 2012 21:16:23 +0200 Subject: [PATCH 101/252] nfs4: Use correct mode in share reclaimation --- .../kernel/file_systems/nfs4/Inode.cpp | 16 ------------ .../kernel/file_systems/nfs4/NFS4Defs.h | 25 ++++++++++++++++--- .../kernel/file_systems/nfs4/NFS4Server.cpp | 2 +- 3 files changed, 22 insertions(+), 21 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index 3d3a56ba44..08a9fe8386 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -647,22 +647,6 @@ Inode::WriteStat(const struct stat* st, uint32 mask) } -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) { diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h index 5ae3b149ad..813586a667 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h @@ -166,6 +166,23 @@ enum OpenAccess { OPEN4_SHARE_ACCESS_BOTH = 3 }; + +static inline 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; +} + + enum OpenCreate { OPEN4_NOCREATE = 0, OPEN4_CREATE = 1 @@ -203,8 +220,8 @@ enum LockType { }; -static inline -LockType sGetLockType(short type, bool wait) { +static inline LockType +sGetLockType(short type, bool wait) { switch (type) { case F_RDLCK: return wait ? READW_LT : READ_LT; case F_WRLCK: return wait ? WRITEW_LT : WRITE_LT; @@ -213,8 +230,8 @@ LockType sGetLockType(short type, bool wait) { } -static inline -short sLockTypeToHaiku(LockType type) { +static inline short +sLockTypeToHaiku(LockType type) { switch (type) { case READ_LT: case READW_LT: diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp index 0d071de338..4c30554aa2 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp @@ -78,7 +78,7 @@ NFS4Server::_ReclaimOpen(OpenFileCookie* cookie) RequestBuilder& req = request.Builder(); req.PutFH(cookie->fHandle); - req.Open(CLAIM_PREVIOUS, cookie->fSequence++, OPEN4_SHARE_ACCESS_READ, + req.Open(CLAIM_PREVIOUS, cookie->fSequence++, sModeToAccess(cookie->fMode), cookie->fClientId, OPEN4_NOCREATE, cookie->fOwnerId, NULL); status_t result = request.Send(); From 2f03ff09af62ad9036c0c90d6388de860deaf7ca Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Thu, 28 Jun 2012 22:46:30 +0200 Subject: [PATCH 102/252] nfs4: Add full support for lease migration --- .../kernel/file_systems/nfs4/Filesystem.cpp | 140 +++------------ .../kernel/file_systems/nfs4/Filesystem.h | 23 ++- .../kernel/file_systems/nfs4/Inode.cpp | 22 +-- src/add-ons/kernel/file_systems/nfs4/Inode.h | 2 +- src/add-ons/kernel/file_systems/nfs4/Jamfile | 1 + .../kernel/file_systems/nfs4/NFS4Server.cpp | 26 ++- .../kernel/file_systems/nfs4/NFS4Server.h | 1 + .../kernel/file_systems/nfs4/RootInode.cpp | 160 ++++++++++++++++++ .../kernel/file_systems/nfs4/RootInode.h | 28 +++ .../file_systems/nfs4/kernel_interface.cpp | 20 ++- 10 files changed, 278 insertions(+), 145 deletions(-) create mode 100644 src/add-ons/kernel/file_systems/nfs4/RootInode.cpp create mode 100644 src/add-ons/kernel/file_systems/nfs4/RootInode.h diff --git a/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp b/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp index 0f07306cd6..fc2a6d74b9 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp @@ -16,7 +16,7 @@ #include #include "Request.h" -#include "Inode.h" +#include "RootInode.h" extern RPC::ServerManager* gRPCServerManager; @@ -30,7 +30,7 @@ Filesystem::Filesystem() fOpenFiles(NULL), fOpenCount(0), fPath(NULL), - fName(NULL), + fRoot(NULL), fId(1) { mutex_init(&fOpenLock, NULL); @@ -43,8 +43,8 @@ Filesystem::~Filesystem() mutex_destroy(&fOpenLock); - free(const_cast(fName)); free(const_cast(fPath)); + delete fRoot; } @@ -155,33 +155,39 @@ Filesystem::Mount(Filesystem** pfs, RPC::Server* serv, const char* fsPath, } else fs->fPath = NULL; + FileInfo fi; const char* name; if (fsPath != NULL && fsPath[0] == '/') fsPath++; name = strrchr(fsPath, '/'); if (name != NULL) { name++; - fs->fName = strdup(name); + fi.fName = strdup(name); } else - fs->fName = strdup(fsPath); + fi.fName = strdup(fsPath); - memcpy(&fs->fRootFH, &fh, sizeof(Filehandle)); fs->fServer = serv; fs->fDevId = id; fs->fFsId = *fsid; - FileInfo fi; fi.fFH = fh; fi.fParent = fh; - fi.fName = strdup("/"); fi.fPath = strdup(sGetPath(fs->fPath, fsPath)); - fs->fRoot = fi; - - *pfs = fs; delete[] values; + Inode* inode; + result = Inode::CreateInode(fs, fi, &inode); + if (result != B_OK) { + delete fs; + return result; + } + + fs->fRoot = reinterpret_cast(inode); + fs->NFSServer()->AddFilesystem(fs); + *pfs = fs; + return B_OK; } @@ -207,115 +213,19 @@ Filesystem::GetInode(ino_t id, Inode** _inode) } -Inode* -Filesystem::CreateRootInode() -{ - Inode* inode; - status_t result = Inode::CreateInode(this, fRoot, &inode); - if (result == B_OK) - return inode; - else - return NULL; -} - - status_t -Filesystem::ReadInfo(struct fs_info* info) +Filesystem::Migrate(const RPC::Server* serv) { - Request request(fServer); - RequestBuilder& req = request.Builder(); - - req.PutFH(fRootFH); - Attribute attr[] = { FATTR4_FILES_FREE, FATTR4_FILES_TOTAL, - FATTR4_MAXREAD, FATTR4_MAXWRITE, FATTR4_SPACE_FREE, - FATTR4_SPACE_TOTAL }; - req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); - - status_t result = request.Send(); - if (result != B_OK) - return result; - - ReplyInterpreter& reply = request.Reply(); - - reply.PutFH(); - - AttrValue* values; - uint32 count, next = 0; - result = reply.GetAttr(&values, &count); - if (result != B_OK) - return result; - - if (count >= next && values[next].fAttribute == FATTR4_FILES_FREE) { - info->free_nodes = values[next].fData.fValue64; - next++; - } - - if (count >= next && values[next].fAttribute == FATTR4_FILES_TOTAL) { - info->total_nodes = values[next].fData.fValue64; - next++; - } - - uint64 io_size = LONGLONG_MAX; - if (count >= next && values[next].fAttribute == FATTR4_MAXREAD) { - io_size = min_c(io_size, values[next].fData.fValue64); - next++; - } - - if (count >= next && values[next].fAttribute == FATTR4_MAXWRITE) { - io_size = min_c(io_size, values[next].fData.fValue64); - next++; - } - - if (io_size == LONGLONG_MAX) - io_size = 32768; - info->io_size = io_size; - info->block_size = io_size; - - if (count >= next && values[next].fAttribute == FATTR4_SPACE_FREE) { - info->free_blocks = values[next].fData.fValue64 / io_size; - next++; - } - - if (count >= next && values[next].fAttribute == FATTR4_SPACE_TOTAL) { - info->total_blocks = values[next].fData.fValue64 / io_size; - next++; - } - - info->flags = B_FS_IS_READONLY; - strncpy(info->volume_name, fName, B_FILE_NAME_LENGTH); - - delete[] values; - - return B_OK; -} - - -status_t -Filesystem::Migrate(const Filehandle& fh, const RPC::Server* serv) -{ - MutexLocker _(fMigrationLock); + MutexLocker _(fOpenLock); if (serv != fServer) return B_OK; - Request request(fServer); - RequestBuilder& req = request.Builder(); - - req.PutFH(fh); - Attribute attr[] = { FATTR4_FS_LOCATIONS }; - req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); - - status_t result = request.Send(); - if (result != B_OK) - return result; - - ReplyInterpreter& reply = request.Reply(); - - reply.PutFH(); + if (!fRoot->ProbeMigration()) + return B_OK; AttrValue* values; - uint32 count; - result = reply.GetAttr(&values, &count); - if (result != B_OK || count < 1) + status_t result = fRoot->GetLocations(&values); + if (result != B_OK) return result; FSLocations* locs = @@ -358,6 +268,10 @@ Filesystem::Migrate(const Filehandle& fh, const RPC::Server* serv) if (server == fServer) return B_ERROR; + NFS4Server* old = reinterpret_cast(server->PrivateData()); + old->RemoveFilesystem(this); + NFSServer()->AddFilesystem(this); + gRPCServerManager->Release(server); return B_OK; diff --git a/src/add-ons/kernel/file_systems/nfs4/Filesystem.h b/src/add-ons/kernel/file_systems/nfs4/Filesystem.h index e115dd47ff..9073e67169 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Filesystem.h +++ b/src/add-ons/kernel/file_systems/nfs4/Filesystem.h @@ -9,15 +9,13 @@ #define FILESYSTEM_H -#include - #include "InodeIdMap.h" #include "NFS4Defs.h" #include "NFS4Server.h" class Inode; -class InodeIdMap; +class RootInode; class Filesystem { public: @@ -26,12 +24,9 @@ public: ~Filesystem(); status_t GetInode(ino_t id, Inode** inode); - Inode* CreateRootInode(); + inline Inode* Root(); - status_t ReadInfo(struct fs_info* info); - - status_t Migrate(const Filehandle& fh, - const RPC::Server* serv); + status_t Migrate(const RPC::Server* serv); OpenFileCookie* OpenFilesLock(); void OpenFilesUnlock(); @@ -67,11 +62,8 @@ private: FilesystemId fFsId; const char* fPath; - mutex fMigrationLock; - const char* fName; - FileInfo fRoot; - Filehandle fRootFH; + RootInode* fRoot; RPC::Server* fServer; @@ -82,6 +74,13 @@ private: }; +inline Inode* +Filesystem::Root() +{ + return reinterpret_cast(fRoot); +} + + inline uint32 Filesystem::OpenFilesCount() { diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index 08a9fe8386..5c72de93c6 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -15,6 +15,7 @@ #include #include "Request.h" +#include "RootInode.h" Inode::Inode() @@ -25,7 +26,12 @@ Inode::Inode() status_t Inode::CreateInode(Filesystem* fs, const FileInfo &fi, Inode** _inode) { - Inode* inode = new(std::nothrow) Inode; + Inode* inode = NULL; + if (fs->Root() == NULL) + inode = new(std::nothrow) RootInode; + else + inode = new(std::nothrow) Inode; + if (inode == NULL) return B_NO_MEMORY; @@ -215,8 +221,7 @@ Inode::Link(Inode* dir, const char* name) // filesystem has been moved if (reply.NFS4Error() == NFS4ERR_MOVED) { - fFilesystem->Migrate(fHandle, serv); - dir->fFilesystem->Migrate(dir->fHandle, serv); + fFilesystem->Migrate(serv); continue; } @@ -321,8 +326,7 @@ Inode::Rename(Inode* from, Inode* to, const char* fromName, const char* toName) // filesystem has been moved if (reply.NFS4Error() == NFS4ERR_MOVED) { - from->fFilesystem->Migrate(from->fHandle, serv); - to->fFilesystem->Migrate(to->fHandle, serv); + from->fFilesystem->Migrate(serv); continue; } @@ -1557,13 +1561,9 @@ Inode::_HandleErrors(uint32 nfs4Error, RPC::Server* serv, return false; // filesystem has been moved - case NFS4ERR_MOVED: - fFilesystem->Migrate(fHandle, serv); - return true; - - // lease has been moved, provoke server to return NFS4ERR_MOVED case NFS4ERR_LEASE_MOVED: - Access(0); + case NFS4ERR_MOVED: + fFilesystem->Migrate(serv); return true; default: diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h b/src/add-ons/kernel/file_systems/nfs4/Inode.h index 1cf1f11dce..56051913ca 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -68,7 +68,7 @@ public: status_t ReleaseAllLocks(OpenFileCookie* cookie); -private: +protected: Inode(); diff --git a/src/add-ons/kernel/file_systems/nfs4/Jamfile b/src/add-ons/kernel/file_systems/nfs4/Jamfile index 6ee1391b40..70b6749ad5 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Jamfile +++ b/src/add-ons/kernel/file_systems/nfs4/Jamfile @@ -13,6 +13,7 @@ KernelAddon nfs4 : ReplyInterpreter.cpp Request.cpp RequestBuilder.cpp + RootInode.cpp RPCAuth.cpp RPCCall.cpp RPCReply.cpp diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp index 4c30554aa2..80a54b545f 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp @@ -213,6 +213,21 @@ NFS4Server::ClientId(uint64 prevId, bool forceNew) } +status_t +NFS4Server::FilesystemMigrated() +{ + // reclaim all opened files and held locks from all filesystems + MutexLocker _(fFSLock); + Filesystem* fs = fFilesystems; + while (fs != NULL) { + fs->Migrate(fServer); + fs = fs->fNext; + } + + return B_OK; +} + + status_t NFS4Server::_GetLeaseTime() { @@ -297,9 +312,14 @@ NFS4Server::_Renewal() request.Builder().Renew(fClientId); request.Send(); - if (request.Reply().NFS4Error() == NFS4ERR_STALE_CLIENTID) - ServerRebooted(clientId); - // TODO: support NFS4ERR_LEASE_MOVED + switch (request.Reply().NFS4Error()) { + case NFS4ERR_STALE_CLIENTID: + ServerRebooted(clientId); + break; + case NFS4ERR_LEASE_MOVED: + FilesystemMigrated(); + break; + } } return B_OK; diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h index a13f642584..feed4e0ce0 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h @@ -23,6 +23,7 @@ public: virtual ~NFS4Server(); uint64 ServerRebooted(uint64 clientId); + status_t FilesystemMigrated(); void AddFilesystem(Filesystem* fs); void RemoveFilesystem(Filesystem* fs); diff --git a/src/add-ons/kernel/file_systems/nfs4/RootInode.cpp b/src/add-ons/kernel/file_systems/nfs4/RootInode.cpp new file mode 100644 index 0000000000..073dee4346 --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/RootInode.cpp @@ -0,0 +1,160 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ + + +#include "RootInode.h" + +#include + +#include "Request.h" + + +status_t +RootInode::ReadInfo(struct fs_info* info) +{ + do { + RPC::Server* serv = fFilesystem->Server(); + Request request(serv); + RequestBuilder& req = request.Builder(); + + req.PutFH(fHandle); + Attribute attr[] = { FATTR4_FILES_FREE, FATTR4_FILES_TOTAL, + FATTR4_MAXREAD, FATTR4_MAXWRITE, FATTR4_SPACE_FREE, + FATTR4_SPACE_TOTAL }; + req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); + + status_t result = request.Send(); + if (result != B_OK) + return result; + + ReplyInterpreter& reply = request.Reply(); + + if (_HandleErrors(reply.NFS4Error(), serv)) + continue; + + reply.PutFH(); + + AttrValue* values; + uint32 count, next = 0; + result = reply.GetAttr(&values, &count); + if (result != B_OK) + return result; + + if (count >= next && values[next].fAttribute == FATTR4_FILES_FREE) { + info->free_nodes = values[next].fData.fValue64; + next++; + } + + if (count >= next && values[next].fAttribute == FATTR4_FILES_TOTAL) { + info->total_nodes = values[next].fData.fValue64; + next++; + } + + uint64 io_size = LONGLONG_MAX; + if (count >= next && values[next].fAttribute == FATTR4_MAXREAD) { + io_size = min_c(io_size, values[next].fData.fValue64); + next++; + } + + if (count >= next && values[next].fAttribute == FATTR4_MAXWRITE) { + io_size = min_c(io_size, values[next].fData.fValue64); + next++; + } + + if (io_size == LONGLONG_MAX) + io_size = 32768; + info->io_size = io_size; + info->block_size = io_size; + + if (count >= next && values[next].fAttribute == FATTR4_SPACE_FREE) { + info->free_blocks = values[next].fData.fValue64 / io_size; + next++; + } + + if (count >= next && values[next].fAttribute == FATTR4_SPACE_TOTAL) { + info->total_blocks = values[next].fData.fValue64 / io_size; + next++; + } + + delete[] values; + + break; + } while (true); + + info->flags = 0; + strncpy(info->volume_name, fName, B_FILE_NAME_LENGTH); + + return B_OK; +} + + +bool +RootInode::ProbeMigration() +{ + do { + RPC::Server* serv = fFilesystem->Server(); + Request request(serv); + RequestBuilder& req = request.Builder(); + + req.PutFH(fHandle); + req.Access(); + + status_t result = request.Send(); + if (result != B_OK) + continue; + + ReplyInterpreter& reply = request.Reply(); + + if (reply.NFS4Error() == NFS4ERR_MOVED) + return true; + + if (_HandleErrors(reply.NFS4Error(), serv)) + continue; + + return false; + } while (true); +} + + + +status_t +RootInode::GetLocations(AttrValue** attrv) +{ + do { + RPC::Server* serv = fFilesystem->Server(); + Request request(serv); + RequestBuilder& req = request.Builder(); + + req.PutFH(fHandle); + Attribute attr[] = { FATTR4_FS_LOCATIONS }; + req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); + + status_t result = request.Send(); + if (result != B_OK) + return result; + + ReplyInterpreter& reply = request.Reply(); + + if (_HandleErrors(reply.NFS4Error(), serv)) + continue; + + reply.PutFH(); + + uint32 count; + result = reply.GetAttr(attrv, &count); + if (result != B_OK) + return result; + if (count < 1) + return B_ERROR; + return B_OK; + + } while (true); + + return B_OK; +} + diff --git a/src/add-ons/kernel/file_systems/nfs4/RootInode.h b/src/add-ons/kernel/file_systems/nfs4/RootInode.h new file mode 100644 index 0000000000..c2101875e8 --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/RootInode.h @@ -0,0 +1,28 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ +#ifndef ROOTINODE_H +#define ROOTINODE_H + + +#include + +#include "Inode.h" + + +class RootInode : public Inode { +public: + status_t ReadInfo(struct fs_info* info); + + bool ProbeMigration(); + status_t GetLocations(AttrValue** attr); + +}; + + +#endif // ROOTINODE_H + 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 9eee937ebd..b8519ffb0a 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -14,12 +14,13 @@ #include #include "Connection.h" -#include "RPCServer.h" -#include "NFS4Defs.h" +#include "Filesystem.h" #include "Inode.h" +#include "NFS4Defs.h" #include "RequestBuilder.h" #include "ReplyInterpreter.h" -#include "Filesystem.h" +#include "RootInode.h" +#include "RPCServer.h" extern fs_volume_ops gNFSv4VolumeOps; @@ -107,7 +108,7 @@ nfs4_mount(fs_volume* volume, const char* device, uint32 flags, return result; } - Inode* inode = fs->CreateRootInode(); + Inode* inode = fs->Root(); if (inode == NULL) { delete fs; gRPCServerManager->Release(server); @@ -166,7 +167,8 @@ static status_t nfs4_read_fs_info(fs_volume* volume, struct fs_info* info) { Filesystem* fs = reinterpret_cast(volume->private_volume); - return fs->ReadInfo(info); + RootInode* inode = reinterpret_cast(fs->Root()); + return inode->ReadInfo(info); } @@ -196,7 +198,11 @@ nfs4_get_vnode_name(fs_volume* volume, fs_vnode* vnode, char* buffer, static status_t nfs4_put_vnode(fs_volume* volume, fs_vnode* vnode, bool reenter) { + Filesystem* fs = reinterpret_cast(volume->private_volume); Inode* inode = reinterpret_cast(vnode->private_node); + if (fs->Root() == inode) + return B_OK; + inode->FileSystem()->InoIdMap()->RemoveEntry(inode->ID()); delete inode; @@ -211,7 +217,11 @@ nfs4_remove_vnode(fs_volume* volume, fs_vnode* vnode, bool reenter) // side are only an attempt to simulate local filesystem. Hence, // this hook is the same as put_vnode(). + Filesystem* fs = reinterpret_cast(volume->private_volume); Inode* inode = reinterpret_cast(vnode->private_node); + if (fs->Root() == inode) + return B_OK; + inode->FileSystem()->InoIdMap()->RemoveEntry(inode->ID()); delete inode; From 2a73e4c578d91aa936a012a930d543154a94a1c0 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Thu, 28 Jun 2012 23:13:45 +0200 Subject: [PATCH 103/252] nfs4: Put file and dir specific code in separate files --- .../kernel/file_systems/nfs4/Inode.cpp | 657 ------------------ src/add-ons/kernel/file_systems/nfs4/Inode.h | 4 +- .../kernel/file_systems/nfs4/InodeDir.cpp | 283 ++++++++ .../kernel/file_systems/nfs4/InodeRegular.cpp | 413 +++++++++++ src/add-ons/kernel/file_systems/nfs4/Jamfile | 2 + 5 files changed, 700 insertions(+), 659 deletions(-) create mode 100644 src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp create mode 100644 src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index 5c72de93c6..37f16c5b56 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -9,7 +9,6 @@ #include "Inode.h" -#include #include #include @@ -651,661 +650,6 @@ Inode::WriteStat(const struct stat* st, uint32 mask) } -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->RemoveOpenFile(cookie); - return result; - } - - ReplyInterpreter& reply = request.Reply(); - - reply.PutFH(); - - result = reply.OpenConfirm(&cookie->fStateSeq); - if (result != B_OK) { - fs->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->fMode = mode; - cookie->fSequence = 0; - cookie->fLocks = NULL; - - 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(fHandle); - - AttrValue cattr[2]; - 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; - req.Open(CLAIM_NULL, cookie->fSequence++, sModeToAccess(mode), - cookie->fClientId, OPEN4_CREATE, cookie->fOwnerId, name, cattr, - i + 1, (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 (_HandleErrors(reply.NFS4Error(), serv)) - continue; - - reply.PutFH(); - reply.Open(cookie->fStateId, &cookie->fStateSeq, &confirm); - 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[1].fData.fValue64; - - delete[] values; - } else - fileId = fFilesystem->AllocFileId(); - - *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); - - cookie->fFilesystem = fFilesystem; - cookie->fHandle = fh; - - break; - } while (true); - - fFilesystem->AddOpenFile(cookie); - - if (confirm) - return sConfirmOpen(fFilesystem, fh, cookie); - else - return B_OK; -} - - -status_t -Inode::Open(int mode, OpenFileCookie* cookie) -{ - bool confirm; - status_t result; - - cookie->fFilesystem = fFilesystem; - cookie->fHandle = fHandle; - cookie->fMode = mode; - cookie->fSequence = 0; - cookie->fLocks = NULL; - - 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); - - // 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(fParentFH); - req.LookUp(fName); - AttrValue attr; - attr.fAttribute = FATTR4_FILEID; - attr.fFreePointer = false; - attr.fData.fValue64 = fFileId; - req.Verify(&attr, 1); - } else if (fFilesystem->ExpireType() == FH4_PERSISTENT) { - req.PutFH(fParentFH); - req.LookUp(fName); - AttrValue attr; - attr.fAttribute = FATTR4_FILEHANDLE; - attr.fFreePointer = true; - attr.fData.fPointer = malloc(sizeof(fHandle)); - memcpy(attr.fData.fPointer, &fHandle, sizeof(fHandle)); - req.Verify(&attr, 1); - } - - req.PutFH(fParentFH); - 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, fName, &attr, - 1, false); - } else - req.Open(CLAIM_NULL, cookie->fSequence++, sModeToAccess(mode), - cookie->fClientId, OPEN4_NOCREATE, cookie->fOwnerId, 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); - - if (confirm) - return sConfirmOpen(fFilesystem, fHandle, cookie); - else - return B_OK; -} - - -status_t -Inode::Close(OpenFileCookie* cookie) -{ - fFilesystem->RemoveOpenFile(cookie); - - do { - RPC::Server* serv = fFilesystem->Server(); - Request request(serv); - RequestBuilder& req = request.Builder(); - - req.PutFH(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; - - return B_OK; - } while (true); - - return B_OK; -} - - -status_t -Inode::Read(OpenFileCookie* cookie, off_t pos, void* buffer, size_t* _length) -{ - bool eof = false; - uint32 size = 0; - uint32 len = 0; - - while (size < *_length && !eof) { - do { - RPC::Server* serv = fFilesystem->Server(); - Request request(serv); - RequestBuilder& req = request.Builder(); - - req.PutFH(fHandle); - req.Read(cookie->fStateId, cookie->fStateSeq, pos + size, - *_length - size); - - status_t result = request.Send(cookie); - if (result != B_OK) - return result; - - ReplyInterpreter& reply = request.Reply(); - - if (_HandleErrors(reply.NFS4Error(), serv, cookie)) - continue; - - reply.PutFH(); - result = reply.Read(reinterpret_cast(buffer) + size, &len, - &eof); - if (result != B_OK) - return result; - - size += len; - - break; - } while (true); - } - - *_length = size; - - return B_OK; -} - - -status_t -Inode::Write(OpenFileCookie* cookie, off_t pos, const void* _buffer, - size_t *_length) -{ - uint32 size = 0; - uint32 len = 0; - uint64 fileSize; - const char* buffer = reinterpret_cast(_buffer); - - while (size < *_length) { - do { - RPC::Server* serv = fFilesystem->Server(); - Request request(serv); - RequestBuilder& req = request.Builder(); - - 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(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; - - ReplyInterpreter& reply = request.Reply(); - - // 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; - - return B_OK; -} - - -status_t -Inode::CreateDir(const char* name, int mode) -{ - do { - RPC::Server* serv = fFilesystem->Server(); - Request request(serv); - RequestBuilder& req = request.Builder(); - - req.PutFH(fHandle); - - AttrValue attr; - attr.fAttribute = FATTR4_MODE; - attr.fFreePointer = false; - attr.fData.fValue32 = mode; - req.Create(NF4DIR, name, &attr, 1); - - 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.Create(); - } while (true); -} - - -status_t -Inode::OpenDir(OpenDirCookie* cookie) -{ - if (fType != NF4DIR) - return B_NOT_A_DIRECTORY; - - do { - RPC::Server* serv = fFilesystem->Server(); - Request request(serv); - RequestBuilder& req = request.Builder(); - - req.PutFH(fHandle); - req.Access(); - - status_t result = request.Send(); - 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->fCookie = 0; - cookie->fCookieVerf = 2; - - return B_OK; - } while (true); -} - - -status_t -Inode::_ReadDirOnce(DirEntry** dirents, uint32* count, OpenDirCookie* cookie, - bool* eof) -{ - do { - RPC::Server* serv = fFilesystem->Server(); - Request request(serv); - RequestBuilder& req = request.Builder(); - - req.PutFH(fHandle); - - Attribute attr[] = { FATTR4_FSID, FATTR4_FILEID }; - req.ReadDir(*count, cookie->fCookie, cookie->fCookieVerf, attr, - sizeof(attr) / 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(); - return reply.ReadDir(&cookie->fCookie, &cookie->fCookieVerf, dirents, - count, eof); - } while (true); -} - - -status_t -Inode::_FillDirEntry(struct dirent* de, ino_t id, const char* name, uint32 pos, - uint32 size) -{ - uint32 nameSize = strlen(name); - const uint32 entSize = sizeof(struct dirent); - - if (pos + entSize + nameSize > size) - return B_BUFFER_OVERFLOW; - - de->d_dev = fFilesystem->DevId(); - de->d_ino = id; - de->d_reclen = entSize + nameSize; - if (de->d_reclen % 8 != 0) - de->d_reclen += 8 - de->d_reclen % 8; - - strcpy(de->d_name, name); - - return B_OK; -} - - -status_t -Inode::_ReadDirUp(struct dirent* de, uint32 pos, uint32 size) -{ - do { - RPC::Server* serv = fFilesystem->Server(); - Request request(serv); - RequestBuilder& req = request.Builder(); - - req.PutFH(fHandle); - req.LookUpUp(); - req.GetFH(); - - if (fFilesystem->IsAttrSupported(FATTR4_FILEID)) { - 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 (_HandleErrors(reply.NFS4Error(), serv)) - continue; - - reply.PutFH(); - result = reply.LookUpUp(); - if (result != B_OK) - return result; - - Filehandle fh; - reply.GetFH(&fh); - - uint64 fileId; - if (fFilesystem->IsAttrSupported(FATTR4_FILEID)) { - AttrValue* values; - uint32 count; - reply.GetAttr(&values, &count); - if (result != B_OK) - return result; - - fileId = values[0].fData.fValue64; - delete[] values; - } else - fileId = fFilesystem->AllocFileId(); - - return _FillDirEntry(de, _FileIdToInoT(fileId), "..", pos, size); - } while (true); -} - -// TODO: Currently inode numbers returned by ReadDir are virtually random. -// Apparently Haiku does not use that information (contrary to inode number -// returned by LookUp) so fixing it can wait until directory caches are -// implemented. -// When directories are cached client should store inode numbers it assigned -// to directroy entries and use them consequently. -status_t -Inode::ReadDir(void* _buffer, uint32 size, uint32* _count, - OpenDirCookie* cookie) -{ - uint32 count = 0; - uint32 pos = 0; - uint32 this_count; - bool eof = false; - - char* buffer = reinterpret_cast(_buffer); - - if (cookie->fCookie == 0 && cookie->fCookieVerf == 2 && count < *_count) { - struct dirent* de = reinterpret_cast(buffer + pos); - - _FillDirEntry(de, fFileId, ".", pos, size); - - pos += de->d_reclen; - count++; - cookie->fCookieVerf--; - } - - if (cookie->fCookie == 0 && cookie->fCookieVerf == 1 && count < *_count) { - struct dirent* de = reinterpret_cast(buffer + pos); - - if (strcmp(fName, "/")) - _ReadDirUp(de, pos, size); - else - _FillDirEntry(de, _FileIdToInoT(fFileId), "..", pos, size); - - pos += de->d_reclen; - count++; - cookie->fCookieVerf--; - } - - bool overflow = false; - while (count < *_count && !eof) { - this_count = *_count - count; - DirEntry* dirents; - - status_t result = _ReadDirOnce(&dirents, &this_count, cookie, &eof); - if (result != B_OK) - return result; - - uint32 i, entries = 0; - for (i = 0; i < min_c(this_count, *_count - count); i++) { - struct dirent* de = reinterpret_cast(buffer + pos); - - // FATTR4_FSID is mandatory - void* data = dirents[i].fAttrs[0].fData.fPointer; - FilesystemId* fsid = reinterpret_cast(data); - if (*fsid != fFilesystem->FsId()) - continue; - - ino_t id; - if (dirents[i].fAttrCount == 2) - id = _FileIdToInoT(dirents[i].fAttrs[1].fData.fValue64); - else - id = _FileIdToInoT(fFilesystem->AllocFileId()); - - const char* name = dirents[i].fName; - if (_FillDirEntry(de, id, name, pos, size) == B_BUFFER_OVERFLOW) { - eof = true; - overflow = true; - break; - } - - pos += de->d_reclen; - entries++; - } - delete[] dirents; - count += entries; - } - - if (count == 0 && overflow) - return B_BUFFER_OVERFLOW; - - *_count = count; - - return B_OK; -} - - status_t Inode::TestLock(OpenFileCookie* cookie, struct flock* lock) { @@ -1501,7 +845,6 @@ Inode::ReleaseAllLocks(OpenFileCookie* cookie) } - bool Inode::_HandleErrors(uint32 nfs4Error, RPC::Server* serv, OpenFileCookie* cookie) diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h b/src/add-ons/kernel/file_systems/nfs4/Inode.h index 56051913ca..4beed54e1f 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -71,13 +71,13 @@ public: protected: Inode(); - bool _HandleErrors(uint32 nfs4Error, RPC::Server* serv, OpenFileCookie* cookie = NULL); - status_t _LookUpFilehandle(); + status_t _ConfirmOpen(OpenFileCookie* cookie); + status_t _ReadDirOnce(DirEntry** dirents, uint32* count, OpenDirCookie* cookie, bool* eof); status_t _FillDirEntry(struct dirent* de, ino_t id, diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp b/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp new file mode 100644 index 0000000000..290c56fb6a --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp @@ -0,0 +1,283 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ + + +#include "Inode.h" + +#include +#include + +#include "Request.h" +#include "RootInode.h" + + +status_t +Inode::CreateDir(const char* name, int mode) +{ + do { + RPC::Server* serv = fFilesystem->Server(); + Request request(serv); + RequestBuilder& req = request.Builder(); + + req.PutFH(fHandle); + + AttrValue attr; + attr.fAttribute = FATTR4_MODE; + attr.fFreePointer = false; + attr.fData.fValue32 = mode; + req.Create(NF4DIR, name, &attr, 1); + + 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.Create(); + } while (true); +} + + +status_t +Inode::OpenDir(OpenDirCookie* cookie) +{ + if (fType != NF4DIR) + return B_NOT_A_DIRECTORY; + + do { + RPC::Server* serv = fFilesystem->Server(); + Request request(serv); + RequestBuilder& req = request.Builder(); + + req.PutFH(fHandle); + req.Access(); + + status_t result = request.Send(); + 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->fCookie = 0; + cookie->fCookieVerf = 2; + + return B_OK; + } while (true); +} + + +status_t +Inode::_ReadDirOnce(DirEntry** dirents, uint32* count, OpenDirCookie* cookie, + bool* eof) +{ + do { + RPC::Server* serv = fFilesystem->Server(); + Request request(serv); + RequestBuilder& req = request.Builder(); + + req.PutFH(fHandle); + + Attribute attr[] = { FATTR4_FSID, FATTR4_FILEID }; + req.ReadDir(*count, cookie->fCookie, cookie->fCookieVerf, attr, + sizeof(attr) / 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(); + return reply.ReadDir(&cookie->fCookie, &cookie->fCookieVerf, dirents, + count, eof); + } while (true); +} + + +status_t +Inode::_FillDirEntry(struct dirent* de, ino_t id, const char* name, uint32 pos, + uint32 size) +{ + uint32 nameSize = strlen(name); + const uint32 entSize = sizeof(struct dirent); + + if (pos + entSize + nameSize > size) + return B_BUFFER_OVERFLOW; + + de->d_dev = fFilesystem->DevId(); + de->d_ino = id; + de->d_reclen = entSize + nameSize; + if (de->d_reclen % 8 != 0) + de->d_reclen += 8 - de->d_reclen % 8; + + strcpy(de->d_name, name); + + return B_OK; +} + + +status_t +Inode::_ReadDirUp(struct dirent* de, uint32 pos, uint32 size) +{ + do { + RPC::Server* serv = fFilesystem->Server(); + Request request(serv); + RequestBuilder& req = request.Builder(); + + req.PutFH(fHandle); + req.LookUpUp(); + req.GetFH(); + + if (fFilesystem->IsAttrSupported(FATTR4_FILEID)) { + 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 (_HandleErrors(reply.NFS4Error(), serv)) + continue; + + reply.PutFH(); + result = reply.LookUpUp(); + if (result != B_OK) + return result; + + Filehandle fh; + reply.GetFH(&fh); + + uint64 fileId; + if (fFilesystem->IsAttrSupported(FATTR4_FILEID)) { + AttrValue* values; + uint32 count; + reply.GetAttr(&values, &count); + if (result != B_OK) + return result; + + fileId = values[0].fData.fValue64; + delete[] values; + } else + fileId = fFilesystem->AllocFileId(); + + return _FillDirEntry(de, _FileIdToInoT(fileId), "..", pos, size); + } while (true); +} + +// TODO: Currently inode numbers returned by ReadDir are virtually random. +// Apparently Haiku does not use that information (contrary to inode number +// returned by LookUp) so fixing it can wait until directory caches are +// implemented. +// When directories are cached client should store inode numbers it assigned +// to directroy entries and use them consequently. +status_t +Inode::ReadDir(void* _buffer, uint32 size, uint32* _count, + OpenDirCookie* cookie) +{ + uint32 count = 0; + uint32 pos = 0; + uint32 this_count; + bool eof = false; + + char* buffer = reinterpret_cast(_buffer); + + if (cookie->fCookie == 0 && cookie->fCookieVerf == 2 && count < *_count) { + struct dirent* de = reinterpret_cast(buffer + pos); + + _FillDirEntry(de, fFileId, ".", pos, size); + + pos += de->d_reclen; + count++; + cookie->fCookieVerf--; + } + + if (cookie->fCookie == 0 && cookie->fCookieVerf == 1 && count < *_count) { + struct dirent* de = reinterpret_cast(buffer + pos); + + if (strcmp(fName, "/")) + _ReadDirUp(de, pos, size); + else + _FillDirEntry(de, _FileIdToInoT(fFileId), "..", pos, size); + + pos += de->d_reclen; + count++; + cookie->fCookieVerf--; + } + + bool overflow = false; + while (count < *_count && !eof) { + this_count = *_count - count; + DirEntry* dirents; + + status_t result = _ReadDirOnce(&dirents, &this_count, cookie, &eof); + if (result != B_OK) + return result; + + uint32 i, entries = 0; + for (i = 0; i < min_c(this_count, *_count - count); i++) { + struct dirent* de = reinterpret_cast(buffer + pos); + + // FATTR4_FSID is mandatory + void* data = dirents[i].fAttrs[0].fData.fPointer; + FilesystemId* fsid = reinterpret_cast(data); + if (*fsid != fFilesystem->FsId()) + continue; + + ino_t id; + if (dirents[i].fAttrCount == 2) + id = _FileIdToInoT(dirents[i].fAttrs[1].fData.fValue64); + else + id = _FileIdToInoT(fFilesystem->AllocFileId()); + + const char* name = dirents[i].fName; + if (_FillDirEntry(de, id, name, pos, size) == B_BUFFER_OVERFLOW) { + eof = true; + overflow = true; + break; + } + + pos += de->d_reclen; + entries++; + } + delete[] dirents; + count += entries; + } + + if (count == 0 && overflow) + return B_BUFFER_OVERFLOW; + + *_count = count; + + return B_OK; +} + diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp new file mode 100644 index 0000000000..3e95ec1eb6 --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp @@ -0,0 +1,413 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ + + +#include "Inode.h" + +#include + +#include + +#include "Request.h" + + +status_t +Inode::_ConfirmOpen(OpenFileCookie* cookie) +{ + do { + RPC::Server* serv = fFilesystem->Server(); + Request request(serv); + + RequestBuilder& req = request.Builder(); + + req.PutFH(fHandle); + 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 +Inode::Create(const char* name, int mode, int perms, OpenFileCookie* cookie, + ino_t* id) +{ + bool confirm; + status_t result; + + cookie->fMode = mode; + cookie->fSequence = 0; + cookie->fLocks = NULL; + + 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(fHandle); + + AttrValue cattr[2]; + 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; + req.Open(CLAIM_NULL, cookie->fSequence++, sModeToAccess(mode), + cookie->fClientId, OPEN4_CREATE, cookie->fOwnerId, name, cattr, + i + 1, (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 (_HandleErrors(reply.NFS4Error(), serv)) + continue; + + reply.PutFH(); + reply.Open(cookie->fStateId, &cookie->fStateSeq, &confirm); + 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[1].fData.fValue64; + + delete[] values; + } else + fileId = fFilesystem->AllocFileId(); + + *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); + + cookie->fFilesystem = fFilesystem; + cookie->fHandle = fh; + + break; + } while (true); + + fFilesystem->AddOpenFile(cookie); + + if (confirm) + return _ConfirmOpen(cookie); + else + return B_OK; +} + + +status_t +Inode::Open(int mode, OpenFileCookie* cookie) +{ + bool confirm; + status_t result; + + cookie->fFilesystem = fFilesystem; + cookie->fHandle = fHandle; + cookie->fMode = mode; + cookie->fSequence = 0; + cookie->fLocks = NULL; + + 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); + + // 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(fParentFH); + req.LookUp(fName); + AttrValue attr; + attr.fAttribute = FATTR4_FILEID; + attr.fFreePointer = false; + attr.fData.fValue64 = fFileId; + req.Verify(&attr, 1); + } else if (fFilesystem->ExpireType() == FH4_PERSISTENT) { + req.PutFH(fParentFH); + req.LookUp(fName); + AttrValue attr; + attr.fAttribute = FATTR4_FILEHANDLE; + attr.fFreePointer = true; + attr.fData.fPointer = malloc(sizeof(fHandle)); + memcpy(attr.fData.fPointer, &fHandle, sizeof(fHandle)); + req.Verify(&attr, 1); + } + + req.PutFH(fParentFH); + 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, fName, &attr, + 1, false); + } else + req.Open(CLAIM_NULL, cookie->fSequence++, sModeToAccess(mode), + cookie->fClientId, OPEN4_NOCREATE, cookie->fOwnerId, 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); + + if (confirm) + return _ConfirmOpen(cookie); + else + return B_OK; +} + + +status_t +Inode::Close(OpenFileCookie* cookie) +{ + fFilesystem->RemoveOpenFile(cookie); + + do { + RPC::Server* serv = fFilesystem->Server(); + Request request(serv); + RequestBuilder& req = request.Builder(); + + req.PutFH(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; + + return B_OK; + } while (true); + + return B_OK; +} + + +status_t +Inode::Read(OpenFileCookie* cookie, off_t pos, void* buffer, size_t* _length) +{ + bool eof = false; + uint32 size = 0; + uint32 len = 0; + + while (size < *_length && !eof) { + do { + RPC::Server* serv = fFilesystem->Server(); + Request request(serv); + RequestBuilder& req = request.Builder(); + + req.PutFH(fHandle); + req.Read(cookie->fStateId, cookie->fStateSeq, pos + size, + *_length - size); + + status_t result = request.Send(cookie); + if (result != B_OK) + return result; + + ReplyInterpreter& reply = request.Reply(); + + if (_HandleErrors(reply.NFS4Error(), serv, cookie)) + continue; + + reply.PutFH(); + result = reply.Read(reinterpret_cast(buffer) + size, &len, + &eof); + if (result != B_OK) + return result; + + size += len; + + break; + } while (true); + } + + *_length = size; + + return B_OK; +} + + +status_t +Inode::Write(OpenFileCookie* cookie, off_t pos, const void* _buffer, + size_t *_length) +{ + uint32 size = 0; + uint32 len = 0; + uint64 fileSize; + const char* buffer = reinterpret_cast(_buffer); + + while (size < *_length) { + do { + RPC::Server* serv = fFilesystem->Server(); + Request request(serv); + RequestBuilder& req = request.Builder(); + + 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(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; + + ReplyInterpreter& reply = request.Reply(); + + // 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; + + return B_OK; +} + diff --git a/src/add-ons/kernel/file_systems/nfs4/Jamfile b/src/add-ons/kernel/file_systems/nfs4/Jamfile index 70b6749ad5..57060a135b 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Jamfile +++ b/src/add-ons/kernel/file_systems/nfs4/Jamfile @@ -8,6 +8,8 @@ KernelAddon nfs4 : Connection.cpp Filesystem.cpp Inode.cpp + InodeDir.cpp + InodeRegular.cpp kernel_interface.cpp NFS4Server.cpp ReplyInterpreter.cpp From 574521e3f0bd627db257165553af97cb40128fcb Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Mon, 2 Jul 2012 19:03:19 +0200 Subject: [PATCH 104/252] nfs4: Use team_id instead of thread_id as lock owner --- src/add-ons/kernel/file_systems/nfs4/Inode.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index 37f16c5b56..5ee4849e43 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -704,7 +704,10 @@ Inode::AcquireLock(OpenFileCookie* cookie, const struct flock* lock, else linfo->fLength = lock->l_len; linfo->fType = sGetLockType(lock->l_type, wait); - linfo->fOwner = find_thread(NULL); + + thread_info info; + get_thread_info(find_thread(NULL), &info); + linfo->fOwner = info.team; do { RPC::Server* serv = fFilesystem->Server(); From 89f0513425b174bc0ec51ca49d3ce0b4384c184b Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Mon, 2 Jul 2012 19:24:40 +0200 Subject: [PATCH 105/252] nfs4: Enforce checking lock type against open mode --- .../kernel/file_systems/nfs4/Inode.cpp | 36 +++++++++++++++++++ src/add-ons/kernel/file_systems/nfs4/Inode.h | 2 ++ 2 files changed, 38 insertions(+) diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index 5ee4849e43..0386cf8173 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -650,9 +650,41 @@ Inode::WriteStat(const struct stat* st, uint32 mask) } +inline status_t +Inode::_CheckLockType(short ltype, uint32 mode) +{ + switch (ltype) { + case F_UNLCK: + return B_OK; + + case F_RDLCK: + if ((mode & O_RDONLY) == 0 && (mode & O_RDWR) == 0) + return EBADF; + else + return B_OK; + + case F_WRLCK: + if ((mode & O_WRONLY) == 0 && (mode & O_RDWR) == 0) + return EBADF; + else + return B_OK; + + default: + return B_BAD_VALUE; + } +} + + status_t Inode::TestLock(OpenFileCookie* cookie, struct flock* lock) { + if (lock->l_type == F_UNLCK) + return B_OK; + + status_t result = _CheckLockType(lock->l_type, cookie->fMode); + if (result != B_OK) + return result; + do { RPC::Server* serv = fFilesystem->Server(); Request request(serv); @@ -693,6 +725,10 @@ status_t Inode::AcquireLock(OpenFileCookie* cookie, const struct flock* lock, bool wait) { + status_t result = _CheckLockType(lock->l_type, cookie->fMode); + if (result != B_OK) + return result; + LockInfo* linfo = new LockInfo; if (linfo == NULL) return B_NO_MEMORY; diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h b/src/add-ons/kernel/file_systems/nfs4/Inode.h index 4beed54e1f..f7f6646384 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -85,6 +85,8 @@ protected: status_t _ReadDirUp(struct dirent* de, uint32 pos, uint32 size); + static inline status_t _CheckLockType(short ltype, uint32 mode); + static inline ino_t _FileIdToInoT(uint64 fileid); uint64 fFileId; From 87d2aacd8b5fc30e4cabf8eb886eb8305f9e8a87 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Mon, 2 Jul 2012 19:27:07 +0200 Subject: [PATCH 106/252] nfs4: Be careful when translating unsigned lock length to signed --- src/add-ons/kernel/file_systems/nfs4/Inode.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index 0386cf8173..7014a8490b 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -709,7 +709,11 @@ Inode::TestLock(OpenFileCookie* cookie, struct flock* lock) if (reply.NFS4Error() == NFS4ERR_DENIED) { lock->l_type = sLockTypeToHaiku(ltype); lock->l_start = static_cast(pos); - lock->l_len = static_cast(len); + if (len >= OFF_MAX) + lock->l_len = OFF_MAX; + else + lock->l_len = static_cast(len); + result = B_OK; } else if (reply.NFS4Error() == NFS4_OK) lock->l_type = F_UNLCK; From 62167cc0dafd86a0bdbf888d010140f6d1cf2370 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Mon, 2 Jul 2012 20:01:42 +0200 Subject: [PATCH 107/252] nfs4: vfs makes sure that l_start + l_len <= OFF_MAX --- src/add-ons/kernel/file_systems/nfs4/Inode.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index 7014a8490b..53a76a453f 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -739,7 +739,7 @@ Inode::AcquireLock(OpenFileCookie* cookie, const struct flock* lock, linfo->fSequence = 0; linfo->fStart = lock->l_start; - if (lock->l_len == OFF_MAX) + if (lock->l_len + lock->l_start == OFF_MAX) linfo->fLength = UINT64_MAX; else linfo->fLength = lock->l_len; From 0f4dcd8bb3017dc29db8bf6de88ebe65c3167ed7 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Mon, 2 Jul 2012 20:09:57 +0200 Subject: [PATCH 108/252] nfs4: OpenConfirm used wrong filehandle --- src/add-ons/kernel/file_systems/nfs4/Inode.h | 3 ++- src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp | 8 ++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h b/src/add-ons/kernel/file_systems/nfs4/Inode.h index f7f6646384..22a6f02036 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -76,7 +76,8 @@ protected: OpenFileCookie* cookie = NULL); status_t _LookUpFilehandle(); - status_t _ConfirmOpen(OpenFileCookie* cookie); + status_t _ConfirmOpen(const Filehandle& fh, + OpenFileCookie* cookie); status_t _ReadDirOnce(DirEntry** dirents, uint32* count, OpenDirCookie* cookie, bool* eof); diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp index 3e95ec1eb6..362db476c5 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp @@ -17,7 +17,7 @@ status_t -Inode::_ConfirmOpen(OpenFileCookie* cookie) +Inode::_ConfirmOpen(const Filehandle& fh, OpenFileCookie* cookie) { do { RPC::Server* serv = fFilesystem->Server(); @@ -25,7 +25,7 @@ Inode::_ConfirmOpen(OpenFileCookie* cookie) RequestBuilder& req = request.Builder(); - req.PutFH(fHandle); + req.PutFH(fh); req.OpenConfirm(cookie->fSequence++, cookie->fStateId, cookie->fStateSeq); @@ -152,7 +152,7 @@ Inode::Create(const char* name, int mode, int perms, OpenFileCookie* cookie, fFilesystem->AddOpenFile(cookie); if (confirm) - return _ConfirmOpen(cookie); + return _ConfirmOpen(fh, cookie); else return B_OK; } @@ -248,7 +248,7 @@ Inode::Open(int mode, OpenFileCookie* cookie) fFilesystem->AddOpenFile(cookie); if (confirm) - return _ConfirmOpen(cookie); + return _ConfirmOpen(fHandle, cookie); else return B_OK; } From 17c2a4858524df47bb37136ec3f1320bafe11430 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Mon, 2 Jul 2012 20:22:41 +0200 Subject: [PATCH 109/252] nfs4: Do not get_vnode() if Inode::Create() failed --- src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) 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 b8519ffb0a..e2b40f9c3d 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -327,8 +327,10 @@ nfs4_create(fs_volume* volume, fs_vnode* dir, const char* name, int openMode, Inode* inode = reinterpret_cast(dir->private_node); status_t result = inode->Create(name, openMode, perms, cookie, _newVnodeID); - if (result != B_OK) + if (result != B_OK) { delete cookie; + return result; + } void* ptr; result = get_vnode(volume, *_newVnodeID, &ptr); From ceed5fe0762ad5e37c023e420f46c913e46f022e Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Mon, 2 Jul 2012 21:07:52 +0200 Subject: [PATCH 110/252] nfs4: Solve confusion between bigtime_t and seconds --- .../kernel/file_systems/nfs4/Inode.cpp | 23 ++++++++++++++----- .../kernel/file_systems/nfs4/NFS4Defs.h | 7 ++++++ .../kernel/file_systems/nfs4/NFS4Server.cpp | 8 +++---- 3 files changed, 28 insertions(+), 10 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index 53a76a453f..dd7ade5340 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -892,6 +892,8 @@ bool Inode::_HandleErrors(uint32 nfs4Error, RPC::Server* serv, OpenFileCookie* cookie) { + uint32 leaseTime; + switch (nfs4Error) { case NFS4_OK: return false; @@ -900,11 +902,12 @@ Inode::_HandleErrors(uint32 nfs4Error, RPC::Server* serv, case NFS4ERR_LOCKED: case NFS4ERR_DELAY: if (cookie == NULL) { - snooze_etc(5 * 1000000, B_SYSTEM_TIMEBASE, B_RELATIVE_TIMEOUT); + 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, 5 * 1000000); + B_RELATIVE_TIMEOUT, sSecToBigTime(5)); if (result == B_TIMED_OUT) return true; else { @@ -916,14 +919,14 @@ Inode::_HandleErrors(uint32 nfs4Error, RPC::Server* serv, // server is in grace period, we need to wait case NFS4ERR_GRACE: + leaseTime = fFilesystem->NFSServer()->LeaseTime(); if (cookie == NULL) { - snooze_etc(fFilesystem->NFSServer()->LeaseTime() / 3, - B_SYSTEM_TIMEBASE, B_RELATIVE_TIMEOUT); + 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, - fFilesystem->NFSServer()->LeaseTime() / 3); + B_RELATIVE_TIMEOUT, sSecToBigTime(leaseTime) / 3); if (result == B_TIMED_OUT) return true; else { @@ -952,6 +955,14 @@ Inode::_HandleErrors(uint32 nfs4Error, RPC::Server* serv, fFilesystem->Migrate(serv); return true; + // lease has expired + case NFS4ERR_EXPIRED: + if (cookie != NULL) { + fFilesystem->NFSServer()->ClientId(cookie->fClientId, true); + return true; + } else + return false; + default: return false; } diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h index 813586a667..f83cc011d4 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h @@ -309,5 +309,12 @@ enum Errors { }; +static inline bigtime_t +sSecToBigTime(uint32 sec) +{ + return static_cast(sec) * 1000000; +} + + #endif // NFS4DEFS_H diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp index 80a54b545f..6fd109e7b3 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp @@ -181,7 +181,7 @@ uint64 NFS4Server::ClientId(uint64 prevId, bool forceNew) { MutexLocker _(fClientIdLock); - if (fClientIdLastUse + (time_t)LeaseTime() < time(NULL) + if (fUseCount == 0 && fClientIdLastUse + (time_t)LeaseTime() < time(NULL) || forceNew && fClientId == prevId) { Request request(fServer); @@ -256,7 +256,7 @@ NFS4Server::_GetLeaseTime() return B_BAD_VALUE; } - fLeaseTime = values[0].fData.fValue32 * 1000000; + fLeaseTime = values[0].fData.fValue32; return B_OK; } @@ -295,8 +295,8 @@ NFS4Server::_Renewal() { while (!fThreadCancel) { // TODO: operations like OPEN, READ, CLOSE, etc also renew leases - snooze_etc(fLeaseTime - 2, B_SYSTEM_TIMEBASE, B_RELATIVE_TIMEOUT - | B_CAN_INTERRUPT); + snooze_etc(sSecToBigTime(fLeaseTime - 2), B_SYSTEM_TIMEBASE, + B_RELATIVE_TIMEOUT | B_CAN_INTERRUPT); uint64 clientId = fClientId; From 43975b3d033bf0795efab438a3f0dc637f479edf Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Mon, 2 Jul 2012 21:10:29 +0200 Subject: [PATCH 111/252] nfs4: Renew ClientId less often --- src/add-ons/kernel/file_systems/nfs4/NFS4Server.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h index feed4e0ce0..2979923bb4 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h @@ -68,6 +68,7 @@ NFS4Server::IncUsage() fUseCount++; if (fThreadCancel) _StartRenewing(); + fClientIdLastUse = time(NULL); } @@ -75,6 +76,7 @@ inline void NFS4Server::DecUsage() { MutexLocker _(fFSLock); + fClientIdLastUse = time(NULL); fUseCount--; } From 62869605c565855e3293809a9974846fa50c423f Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Mon, 2 Jul 2012 23:54:48 +0200 Subject: [PATCH 112/252] nfs4: Add proper lock owners management --- .../kernel/file_systems/nfs4/Cookie.cpp | 116 ++++++++++++++++++ src/add-ons/kernel/file_systems/nfs4/Cookie.h | 34 ++++- .../kernel/file_systems/nfs4/Inode.cpp | 91 +++++++------- .../kernel/file_systems/nfs4/NFS4Server.cpp | 7 ++ .../file_systems/nfs4/ReplyInterpreter.cpp | 18 +-- .../file_systems/nfs4/ReplyInterpreter.h | 2 +- .../file_systems/nfs4/RequestBuilder.cpp | 51 +++++--- 7 files changed, 250 insertions(+), 69 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Cookie.cpp b/src/add-ons/kernel/file_systems/nfs4/Cookie.cpp index 38e6b311c5..ba0398e0d0 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Cookie.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Cookie.cpp @@ -16,6 +16,50 @@ vint64 OpenFileCookie::fLastOwnerId = 0; +LockOwner::LockOwner(uint32 owner) + : + fSequence(0), + fOwner(owner), + fUseCount(0), + fNext(NULL), + fPrev(NULL) +{ + memset(fStateId, 0, sizeof(fStateId)); + mutex_init(&fLock, NULL); +} + + +LockOwner::~LockOwner() +{ + mutex_destroy(&fLock); +} + + +LockInfo::LockInfo(LockOwner* owner) + : + fOwner(owner) +{ + fOwner->fUseCount++; +} + + +LockInfo::~LockInfo() +{ + fOwner->fUseCount--; +} + + +bool +LockInfo::operator==(const struct flock& lock) const +{ + bool eof = lock.l_len + lock.l_start == OFF_MAX; + uint64 start = static_cast(lock.l_start); + uint64 len = static_cast(lock.l_len); + + return fStart == start && fLength == len || eof && fLength == UINT64_MAX; +} + + Cookie::Cookie() : fRequests(NULL), @@ -89,13 +133,85 @@ Cookie::CancelAll() OpenFileCookie::OpenFileCookie() + : + fLockOwners(NULL) { mutex_init(&fLocksLock, NULL); + mutex_init(&fOwnerLock, NULL); } OpenFileCookie::~OpenFileCookie() { mutex_destroy(&fLocksLock); + mutex_destroy(&fOwnerLock); +} + + +LockOwner* +OpenFileCookie::GetLockOwner(uint32 owner) +{ + MutexLocker _(fOwnerLock); + + LockOwner* current = fLockOwners; + while (current != NULL) { + if (current->fOwner == owner) + return current; + + current = current->fNext; + } + + current = new LockOwner(owner); + if (current == NULL) + return NULL; + + current->fClientId = fClientId; + current->fNext = fLockOwners; + if (fLockOwners != NULL) + fLockOwners->fPrev = current; + fLockOwners = current; + + return current; +} + + +// Caller must hold fLocksLock +void +OpenFileCookie::AddLock(LockInfo* lock) +{ + lock->fNext = fLocks; + fLocks = lock; +} + + +// Caller must hold fLocksLock +void +OpenFileCookie::RemoveLock(LockInfo* lock, LockInfo* prev) +{ + if (prev != NULL) + prev->fNext = lock->fNext; + else + fLocks = lock->fNext; +} + + +void +OpenFileCookie::DeleteLock(LockInfo* lock) +{ + MutexLocker _(fOwnerLock); + + LockOwner* owner = lock->fOwner; + delete lock; + + if (owner->fUseCount == 0) { + if (owner->fPrev) + owner->fPrev->fNext = owner->fNext; + else + fLockOwners = owner->fNext; + if (owner->fNext) + owner->fNext->fPrev = owner->fPrev; + + delete owner; + } } diff --git a/src/add-ons/kernel/file_systems/nfs4/Cookie.h b/src/add-ons/kernel/file_systems/nfs4/Cookie.h index e1d9badd4b..d9711a6f5a 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Cookie.h +++ b/src/add-ons/kernel/file_systems/nfs4/Cookie.h @@ -14,18 +14,39 @@ #include "Filesystem.h" -struct LockInfo { +struct LockOwner { + uint64 fClientId; + uint32 fStateId[3]; uint32 fStateSeq; - uint32 fSequence; uint32 fOwner; + + uint32 fUseCount; + + mutex fLock; + + LockOwner* fNext; + LockOwner* fPrev; + + LockOwner(uint32 owner); + ~LockOwner(); +}; + +struct LockInfo { + LockOwner* fOwner; + uint64 fStart; uint64 fLength; LockType fType; LockInfo* fNext; + + LockInfo(LockOwner* owner); + ~LockInfo(); + + bool operator==(const struct flock& lock) const; }; struct Cookie { @@ -65,11 +86,20 @@ struct OpenFileCookie : public Cookie { LockInfo* fLocks; mutex fLocksLock; + LockOwner* fLockOwners; + mutex fOwnerLock; + OpenFileCookie* fNext; OpenFileCookie* fPrev; OpenFileCookie(); ~OpenFileCookie(); + + LockOwner* GetLockOwner(uint32 owner); + + void AddLock(LockInfo* lock); + void RemoveLock(LockInfo* lock, LockInfo* prev); + void DeleteLock(LockInfo* lock); }; struct OpenDirCookie : public Cookie { diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index dd7ade5340..0856e4d017 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -733,11 +733,16 @@ Inode::AcquireLock(OpenFileCookie* cookie, const struct flock* lock, if (result != B_OK) return result; - LockInfo* linfo = new LockInfo; + thread_info info; + get_thread_info(find_thread(NULL), &info); + LockOwner* owner = cookie->GetLockOwner(info.team); + if (owner == NULL) + return B_NO_MEMORY; + + LockInfo* linfo = new LockInfo(owner); if (linfo == NULL) return B_NO_MEMORY; - linfo->fSequence = 0; linfo->fStart = lock->l_start; if (lock->l_len + lock->l_start == OFF_MAX) linfo->fLength = UINT64_MAX; @@ -745,11 +750,9 @@ Inode::AcquireLock(OpenFileCookie* cookie, const struct flock* lock, linfo->fLength = lock->l_len; linfo->fType = sGetLockType(lock->l_type, wait); - thread_info info; - get_thread_info(find_thread(NULL), &info); - linfo->fOwner = info.team; - do { + MutexLocker ownerLocker(linfo->fOwner->fLock); + RPC::Server* serv = fFilesystem->Server(); Request request(serv); RequestBuilder& req = request.Builder(); @@ -759,32 +762,33 @@ Inode::AcquireLock(OpenFileCookie* cookie, const struct flock* lock, status_t result = request.Send(); if (result != B_OK) { - delete linfo; + cookie->DeleteLock(linfo); return result; } ReplyInterpreter &reply = request.Reply(); - if (wait && reply.NFS4Error() == NFS4ERR_DENIED) { - snooze_etc(5 * 1000000, B_SYSTEM_TIMEBASE, B_RELATIVE_TIMEOUT); - continue; - } - - if (_HandleErrors(reply.NFS4Error(), serv, cookie)) - continue; reply.PutFH(); result = reply.Lock(linfo); + + ownerLocker.Unlock(); + if (wait && reply.NFS4Error() == NFS4ERR_DENIED) { + snooze_etc(sSecToBigTime(5), B_SYSTEM_TIMEBASE, + B_RELATIVE_TIMEOUT); + continue; + } + if (_HandleErrors(reply.NFS4Error(), serv, cookie)) + continue; + if (result != B_OK) { - delete linfo; + cookie->DeleteLock(linfo); return result; } - break; } while (true); MutexLocker _(cookie->fLocksLock); - linfo->fNext = cookie->fLocks; - cookie->fLocks = linfo; + cookie->AddLock(linfo); return B_OK; } @@ -794,19 +798,16 @@ status_t Inode::ReleaseLock(OpenFileCookie* cookie, const struct flock* lock) { LockInfo* prev = NULL; - uint32 owner = find_thread(NULL); + + thread_info info; + get_thread_info(find_thread(NULL), &info); + uint32 owner = info.team; MutexLocker locker(cookie->fLocksLock); LockInfo* linfo = cookie->fLocks; while (linfo != NULL) { - if (linfo->fOwner == owner && - linfo->fStart == static_cast(lock->l_start) && - (linfo->fLength == static_cast(lock->l_len) || - (linfo->fLength == UINT64_MAX && lock->l_len == OFF_MAX))) { - if (prev != NULL) - prev->fNext = linfo->fNext; - else - cookie->fLocks = linfo->fNext; + if (linfo->fOwner->fOwner == owner && *linfo == *lock) { + cookie->RemoveLock(linfo, prev); break; } @@ -819,6 +820,8 @@ Inode::ReleaseLock(OpenFileCookie* cookie, const struct flock* lock) return B_BAD_VALUE; do { + MutexLocker ownerLocker(linfo->fOwner->fLock); + RPC::Server* serv = fFilesystem->Server(); Request request(serv); RequestBuilder& req = request.Builder(); @@ -827,23 +830,29 @@ Inode::ReleaseLock(OpenFileCookie* cookie, const struct flock* lock) req.LockU(linfo); status_t result = request.Send(); - if (result != B_OK) + if (result != B_OK) { + cookie->DeleteLock(linfo); return result; + } ReplyInterpreter &reply = request.Reply(); + reply.PutFH(); + result = reply.LockU(linfo); + + ownerLocker.Unlock(); if (_HandleErrors(reply.NFS4Error(), serv, cookie)) continue; - reply.PutFH(); - result = reply.LockU(); - if (result != B_OK) + if (result != B_OK) { + cookie->DeleteLock(linfo); return result; + } break; } while (true); - delete linfo; + cookie->DeleteLock(linfo); return B_OK; } @@ -855,6 +864,8 @@ Inode::ReleaseAllLocks(OpenFileCookie* cookie) MutexLocker _(cookie->fLocksLock); while (cookie->fLocks != NULL) { do { + MutexLocker ownerLocker(cookie->fLocks->fOwner->fLock); + RPC::Server* serv = fFilesystem->Server(); Request request(serv); RequestBuilder& req = request.Builder(); @@ -868,20 +879,18 @@ Inode::ReleaseAllLocks(OpenFileCookie* cookie) ReplyInterpreter &reply = request.Reply(); + reply.PutFH(); + reply.LockU(cookie->fLocks); + + ownerLocker.Unlock(); if (_HandleErrors(reply.NFS4Error(), serv, cookie)) continue; - reply.PutFH(); - result = reply.LockU(); - if (result != B_OK) - return result; - - break; } while (true); - LockInfo* linfo = cookie->fLocks->fNext; - delete cookie->fLocks; - cookie->fLocks = linfo; + LockInfo* linfo = cookie->fLocks; + cookie->RemoveLock(linfo, NULL); + cookie->DeleteLock(linfo); } return B_OK; diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp index 6fd109e7b3..17908e7fa3 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp @@ -121,6 +121,12 @@ NFS4Server::_ReclaimLocks(OpenFileCookie* cookie) MutexLocker _(cookie->fLocksLock); LockInfo* linfo = cookie->fLocks; while (linfo != NULL) { + MutexLocker locker(linfo->fOwner->fLock); + if (linfo->fOwner->fClientId != fClientId) { + memset(linfo->fOwner->fStateId, 0, sizeof(linfo->fOwner->fStateId)); + linfo->fOwner->fClientId = fClientId; + } + do { Request request(fServer); RequestBuilder& req = request.Builder(); @@ -139,6 +145,7 @@ NFS4Server::_ReclaimLocks(OpenFileCookie* cookie) break; } while (true); + locker.Unlock(); linfo = linfo->fNext; } diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp index 471b709016..c5c97c84c5 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp @@ -208,10 +208,10 @@ ReplyInterpreter::Lock(LockInfo* linfo) if (res != B_OK) return res; - linfo->fStateSeq = fReply->Stream().GetUInt(); - linfo->fStateId[0] = fReply->Stream().GetUInt(); - linfo->fStateId[1] = fReply->Stream().GetUInt(); - linfo->fStateId[2] = fReply->Stream().GetUInt(); + linfo->fOwner->fStateSeq = fReply->Stream().GetUInt(); + linfo->fOwner->fStateId[0] = fReply->Stream().GetUInt(); + linfo->fOwner->fStateId[1] = fReply->Stream().GetUInt(); + linfo->fOwner->fStateId[2] = fReply->Stream().GetUInt(); return fReply->Stream().IsEOF() ? B_BAD_VALUE : B_OK; } @@ -236,16 +236,16 @@ ReplyInterpreter::LockT(uint64* pos, uint64* len, LockType* type) status_t -ReplyInterpreter::LockU() +ReplyInterpreter::LockU(LockInfo* linfo) { status_t res = _OperationError(OpLockU); if (res != B_OK) return res; - fReply->Stream().GetUInt(); - fReply->Stream().GetUInt(); - fReply->Stream().GetUInt(); - fReply->Stream().GetUInt(); + linfo->fOwner->fStateSeq = fReply->Stream().GetUInt(); + linfo->fOwner->fStateId[0] = fReply->Stream().GetUInt(); + linfo->fOwner->fStateId[1] = fReply->Stream().GetUInt(); + linfo->fOwner->fStateId[2] = fReply->Stream().GetUInt(); return fReply->Stream().IsEOF() ? B_BAD_VALUE : B_OK; } diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h index b96499f995..c0cbb1dd4d 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h @@ -74,7 +74,7 @@ public: status_t Link(); status_t Lock(LockInfo* linfo); status_t LockT(uint64* pos, uint64* len, LockType* type); - status_t LockU(); + status_t LockU(LockInfo* linfo); inline status_t LookUp(); inline status_t LookUpUp(); inline status_t Nverify(); diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp index 5654c94835..77883fa637 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp @@ -164,19 +164,38 @@ RequestBuilder::Lock(OpenFileCookie* cookie, LockInfo* lock, bool reclaim) fRequest->Stream().AddUHyper(lock->fStart); fRequest->Stream().AddUHyper(lock->fLength); - fRequest->Stream().AddBoolean(true); // new lock owner + if (lock->fOwner->fStateId[0] == 0 && lock->fOwner->fStateId[1] == 0 + && lock->fOwner->fStateId[2] == 0) { - // open seq stateid - fRequest->Stream().AddUInt(cookie->fSequence++); - fRequest->Stream().AddUInt(cookie->fStateSeq); - fRequest->Stream().AddUInt(cookie->fStateId[0]); - fRequest->Stream().AddUInt(cookie->fStateId[1]); - fRequest->Stream().AddUInt(cookie->fStateId[2]); + fRequest->Stream().AddBoolean(true); // new lock owner - // lock seq owner - fRequest->Stream().AddUInt(lock->fSequence++); - fRequest->Stream().AddUHyper(cookie->fClientId); - fRequest->Stream().AddOpaque(&lock->fOwner, sizeof(lock->fOwner)); + // open seq stateid + fRequest->Stream().AddUInt(cookie->fSequence++); + fRequest->Stream().AddUInt(cookie->fStateSeq); + fRequest->Stream().AddUInt(cookie->fStateId[0]); + fRequest->Stream().AddUInt(cookie->fStateId[1]); + fRequest->Stream().AddUInt(cookie->fStateId[2]); + + // lock seq owner + fRequest->Stream().AddUInt(lock->fOwner->fSequence++); + fRequest->Stream().AddUHyper(cookie->fClientId); + + uint64 owner[2]; + owner[0] = lock->fOwner->fOwner; + owner[1] = cookie->fOwnerId; + fRequest->Stream().AddOpaque(owner, sizeof(owner)); + + } else { + fRequest->Stream().AddBoolean(false); // old lock owner + + // lock stateid seq + fRequest->Stream().AddUInt(lock->fOwner->fStateSeq); + fRequest->Stream().AddUInt(lock->fOwner->fStateId[0]); + fRequest->Stream().AddUInt(lock->fOwner->fStateId[1]); + fRequest->Stream().AddUInt(lock->fOwner->fStateId[2]); + + fRequest->Stream().AddUInt(lock->fOwner->fSequence++); + } fOpCount++; @@ -223,11 +242,11 @@ RequestBuilder::LockU(LockInfo* lock) fRequest->Stream().AddInt(lock->fType); - fRequest->Stream().AddUInt(lock->fSequence++); - fRequest->Stream().AddUInt(lock->fStateSeq); - fRequest->Stream().AddUInt(lock->fStateId[0]); - fRequest->Stream().AddUInt(lock->fStateId[1]); - fRequest->Stream().AddUInt(lock->fStateId[2]); + fRequest->Stream().AddUInt(lock->fOwner->fSequence++); + fRequest->Stream().AddUInt(lock->fOwner->fStateSeq); + fRequest->Stream().AddUInt(lock->fOwner->fStateId[0]); + fRequest->Stream().AddUInt(lock->fOwner->fStateId[1]); + fRequest->Stream().AddUInt(lock->fOwner->fStateId[2]); fRequest->Stream().AddUHyper(lock->fStart); fRequest->Stream().AddUHyper(lock->fLength); From 1a0820703b7687877d1eb3d34d9d6b3a12064ddb Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Tue, 3 Jul 2012 01:12:27 +0200 Subject: [PATCH 113/252] nfs4: Allow the server to release unused lock owners --- .../kernel/file_systems/nfs4/Cookie.cpp | 22 ++++++++++- src/add-ons/kernel/file_systems/nfs4/Cookie.h | 3 ++ .../kernel/file_systems/nfs4/Inode.cpp | 24 +++++++----- .../kernel/file_systems/nfs4/NFS4Defs.h | 3 +- .../file_systems/nfs4/ReplyInterpreter.h | 8 ++++ .../file_systems/nfs4/RequestBuilder.cpp | 37 ++++++++++++++++--- .../kernel/file_systems/nfs4/RequestBuilder.h | 7 ++++ 7 files changed, 86 insertions(+), 18 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Cookie.cpp b/src/add-ons/kernel/file_systems/nfs4/Cookie.cpp index ba0398e0d0..6c39b970a9 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Cookie.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Cookie.cpp @@ -134,6 +134,7 @@ Cookie::CancelAll() OpenFileCookie::OpenFileCookie() : + fLocks(NULL), fLockOwners(NULL) { mutex_init(&fLocksLock, NULL); @@ -151,8 +152,6 @@ OpenFileCookie::~OpenFileCookie() LockOwner* OpenFileCookie::GetLockOwner(uint32 owner) { - MutexLocker _(fOwnerLock); - LockOwner* current = fLockOwners; while (current != NULL) { if (current->fOwner == owner) @@ -211,7 +210,26 @@ OpenFileCookie::DeleteLock(LockInfo* lock) if (owner->fNext) owner->fNext->fPrev = owner->fPrev; + _ReleaseLockOwner(owner); delete owner; } } + +status_t +OpenFileCookie::_ReleaseLockOwner(LockOwner* owner) +{ + Request request(fFilesystem->Server()); + RequestBuilder& req = request.Builder(); + + req.ReleaseLockOwner(this, owner); + + status_t result = request.Send(); + if (result != B_OK) + return result; + + ReplyInterpreter &reply = request.Reply(); + + return reply.ReleaseLockOwner(); +} + diff --git a/src/add-ons/kernel/file_systems/nfs4/Cookie.h b/src/add-ons/kernel/file_systems/nfs4/Cookie.h index d9711a6f5a..ef312beb0f 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Cookie.h +++ b/src/add-ons/kernel/file_systems/nfs4/Cookie.h @@ -100,6 +100,9 @@ struct OpenFileCookie : public Cookie { void AddLock(LockInfo* lock); void RemoveLock(LockInfo* lock, LockInfo* prev); void DeleteLock(LockInfo* lock); + +private: + status_t _ReleaseLockOwner(LockOwner* owner); }; struct OpenDirCookie : public Cookie { diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index 0856e4d017..232581d09d 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -735,6 +735,8 @@ Inode::AcquireLock(OpenFileCookie* cookie, const struct flock* lock, thread_info info; get_thread_info(find_thread(NULL), &info); + + MutexLocker locker(cookie->fOwnerLock); LockOwner* owner = cookie->GetLockOwner(info.team); if (owner == NULL) return B_NO_MEMORY; @@ -742,6 +744,7 @@ Inode::AcquireLock(OpenFileCookie* cookie, const struct flock* lock, LockInfo* linfo = new LockInfo(owner); if (linfo == NULL) return B_NO_MEMORY; + locker.Unlock(); linfo->fStart = lock->l_start; if (lock->l_len + lock->l_start == OFF_MAX) @@ -862,35 +865,38 @@ status_t Inode::ReleaseAllLocks(OpenFileCookie* cookie) { MutexLocker _(cookie->fLocksLock); - while (cookie->fLocks != NULL) { + LockInfo* linfo = cookie->fLocks; + while (linfo != NULL) { do { - MutexLocker ownerLocker(cookie->fLocks->fOwner->fLock); + MutexLocker ownerLocker(linfo->fOwner->fLock); RPC::Server* serv = fFilesystem->Server(); Request request(serv); RequestBuilder& req = request.Builder(); req.PutFH(fHandle); - req.LockU(cookie->fLocks); + req.LockU(linfo); status_t result = request.Send(); - if (result != B_OK); - return result; + if (result != B_OK) + break; - ReplyInterpreter &reply = request.Reply(); + ReplyInterpreter& reply = request.Reply(); reply.PutFH(); - reply.LockU(cookie->fLocks); + reply.LockU(linfo); ownerLocker.Unlock(); if (_HandleErrors(reply.NFS4Error(), serv, cookie)) continue; + break; } while (true); - - LockInfo* linfo = cookie->fLocks; + cookie->RemoveLock(linfo, NULL); cookie->DeleteLock(linfo); + + linfo = cookie->fLocks; } return B_OK; diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h index f83cc011d4..853c783d8a 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h @@ -49,7 +49,8 @@ enum Opcode { OpSetClientID = 35, OpSetClientIDConfirm = 36, OpVerify = 37, - OpWrite = 38 + OpWrite = 38, + OpReleaseLockOwner = 39 }; enum Access { diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h index c0cbb1dd4d..0595a8bbbf 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h @@ -95,6 +95,7 @@ public: inline status_t SetClientIDConfirm(); inline status_t Verify(); status_t Write(uint32* size); + inline status_t ReleaseLockOwner(); private: void _ParseHeader(); @@ -206,5 +207,12 @@ ReplyInterpreter::Verify() } +inline status_t +ReplyInterpreter::ReleaseLockOwner() +{ + return _OperationError(OpReleaseLockOwner); +} + + #endif // REPLYINTERPRETER_H diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp index 77883fa637..1f37a9045a 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp @@ -148,6 +148,19 @@ RequestBuilder::GetFH() } +void +RequestBuilder::_GenerateLockOwner(XDR::WriteStream& stream, + OpenFileCookie* cookie, LockOwner* owner) +{ + stream.AddUHyper(cookie->fClientId); + + uint64 lockOwner[2]; + lockOwner[0] = owner->fOwner; + lockOwner[1] = cookie->fOwnerId; + stream.AddOpaque(lockOwner, sizeof(lockOwner)); +} + + status_t RequestBuilder::Lock(OpenFileCookie* cookie, LockInfo* lock, bool reclaim) { @@ -178,12 +191,7 @@ RequestBuilder::Lock(OpenFileCookie* cookie, LockInfo* lock, bool reclaim) // lock seq owner fRequest->Stream().AddUInt(lock->fOwner->fSequence++); - fRequest->Stream().AddUHyper(cookie->fClientId); - - uint64 owner[2]; - owner[0] = lock->fOwner->fOwner; - owner[1] = cookie->fOwnerId; - fRequest->Stream().AddOpaque(owner, sizeof(owner)); + _GenerateLockOwner(fRequest->Stream(), cookie, lock->fOwner); } else { fRequest->Stream().AddBoolean(false); // old lock owner @@ -681,6 +689,23 @@ RequestBuilder::Write(const uint32* id, uint32 stateSeq, const void* buffer, } +status_t +RequestBuilder::ReleaseLockOwner(OpenFileCookie* cookie, LockOwner* owner) +{ + if (fProcedure != ProcCompound) + return B_BAD_VALUE; + if (fRequest == NULL) + return B_NO_MEMORY; + + fRequest->Stream().AddUInt(OpReleaseLockOwner); + _GenerateLockOwner(fRequest->Stream(), cookie, owner); + + fOpCount++; + + return B_OK; +} + + RPC::Call* RequestBuilder::Request() { diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h index 68dbb418f1..0143a9a65d 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h @@ -20,6 +20,7 @@ class OpenFileCookie; class LockInfo; +class LockOwner; class RequestBuilder { public: @@ -72,12 +73,18 @@ public: status_t Write(const uint32* id, uint32 stateSeq, const void* buffer, uint64 pos, uint32 len); + status_t ReleaseLockOwner(OpenFileCookie* cookie, + LockOwner* owner); RPC::Call* Request(); private: void _InitHeader(); + void _GenerateLockOwner(XDR::WriteStream& stream, + OpenFileCookie* cookie, + LockOwner* owner); + void _EncodeAttrs(XDR::WriteStream& stream, AttrValue* attr, uint32 count); void _AttrBitmap(XDR::WriteStream& stream, From a28e873222fd2e506c495feede6fcf7a5425e143 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Tue, 3 Jul 2012 01:33:41 +0200 Subject: [PATCH 114/252] nfs4: Use FileInfo instead of filehandle to identify a file --- src/add-ons/kernel/file_systems/nfs4/Cookie.h | 2 +- .../kernel/file_systems/nfs4/Filehandle.h | 6 +- .../kernel/file_systems/nfs4/Filesystem.cpp | 2 +- .../kernel/file_systems/nfs4/Inode.cpp | 63 +++++++++---------- src/add-ons/kernel/file_systems/nfs4/Inode.h | 12 +--- .../kernel/file_systems/nfs4/InodeDir.cpp | 14 ++--- .../kernel/file_systems/nfs4/InodeRegular.cpp | 44 ++++++------- .../kernel/file_systems/nfs4/NFS4Server.cpp | 6 +- .../kernel/file_systems/nfs4/RootInode.cpp | 8 +-- 9 files changed, 74 insertions(+), 83 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Cookie.h b/src/add-ons/kernel/file_systems/nfs4/Cookie.h index ef312beb0f..cda0791738 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Cookie.h +++ b/src/add-ons/kernel/file_systems/nfs4/Cookie.h @@ -74,7 +74,7 @@ struct OpenFileCookie : public Cookie { uint32 fMode; - Filehandle fHandle; + FileInfo fInfo; uint32 fStateId[3]; uint32 fStateSeq; diff --git a/src/add-ons/kernel/file_systems/nfs4/Filehandle.h b/src/add-ons/kernel/file_systems/nfs4/Filehandle.h index f8a64d3d76..423a72149d 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Filehandle.h +++ b/src/add-ons/kernel/file_systems/nfs4/Filehandle.h @@ -32,7 +32,7 @@ struct Filehandle { // since OPEN requires both parent filehandle and file name (just like LOOKUP). struct FileInfo { uint64 fFileId; - Filehandle fFH; + Filehandle fHandle; Filehandle fParent; const char* fName; @@ -101,7 +101,7 @@ inline FileInfo::FileInfo(const FileInfo& fi) : fFileId(fi.fFileId), - fFH(fi.fFH), + fHandle(fi.fHandle), fParent(fi.fParent), fName(strdup(fi.fName)), fPath(strdup(fi.fPath)) @@ -113,7 +113,7 @@ inline FileInfo& FileInfo::operator=(const FileInfo& fi) { fFileId = fi.fFileId; - fFH = fi.fFH; + fHandle = fi.fHandle; fParent = fi.fParent; free(const_cast(fName)); diff --git a/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp b/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp index fc2a6d74b9..d9a69eb080 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp @@ -170,7 +170,7 @@ Filesystem::Mount(Filesystem** pfs, RPC::Server* serv, const char* fsPath, fs->fDevId = id; fs->fFsId = *fsid; - fi.fFH = fh; + fi.fHandle = fh; fi.fParent = fh; fi.fPath = strdup(sGetPath(fs->fPath, fsPath)); diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index 232581d09d..ea5cc288ac 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -34,18 +34,15 @@ Inode::CreateInode(Filesystem* fs, const FileInfo &fi, Inode** _inode) if (inode == NULL) return B_NO_MEMORY; - inode->fHandle = fi.fFH; + inode->fInfo = fi; inode->fFilesystem = fs; - inode->fParentFH = fi.fParent; - inode->fName = strdup(fi.fName); - inode->fPath = strdup(fi.fPath); do { RPC::Server* serv = fs->Server(); Request request(serv); RequestBuilder& req = request.Builder(); - req.PutFH(inode->fHandle); + req.PutFH(inode->fInfo.fHandle); Attribute attr[] = { FATTR4_TYPE, FATTR4_FSID, FATTR4_FILEID }; req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); @@ -69,11 +66,11 @@ Inode::CreateInode(Filesystem* fs, const FileInfo &fi, Inode** _inode) if (fi.fFileId == 0) { if (count < 3 || values[2].fAttribute != FATTR4_FILEID) - inode->fFileId = fs->AllocFileId(); + inode->fInfo.fFileId = fs->AllocFileId(); else - inode->fFileId = values[2].fData.fValue64; + inode->fInfo.fFileId = values[2].fData.fValue64; } else - inode->fFileId = fi.fFileId; + inode->fInfo.fFileId = fi.fFileId; // FATTR4_TYPE is mandatory inode->fType = values[0].fData.fValue32; @@ -97,7 +94,7 @@ Inode::CreateInode(Filesystem* fs, const FileInfo &fi, Inode** _inode) Inode::~Inode() { - free(const_cast(fName)); + free(const_cast(fInfo.fName)); } @@ -117,7 +114,7 @@ Inode::LookUp(const char* name, ino_t* id) Request request(serv); RequestBuilder& req = request.Builder(); - req.PutFH(fHandle); + req.PutFH(fInfo.fHandle); if (!strcmp(name, "..")) req.LookUpUp(); @@ -174,13 +171,13 @@ Inode::LookUp(const char* name, ino_t* id) FileInfo fi; fi.fFileId = fileId; - fi.fFH = fh; - fi.fParent = fHandle; + fi.fHandle = fh; + fi.fParent = fInfo.fHandle; fi.fName = strdup(name); char* path = reinterpret_cast(malloc(strlen(name) + 2 + - strlen(fPath))); - strcpy(path, fPath); + strlen(fInfo.fPath))); + strcpy(path, fInfo.fPath); strcat(path, "/"); strcat(path, name); fi.fPath = path; @@ -200,9 +197,9 @@ Inode::Link(Inode* dir, const char* name) Request request(serv); RequestBuilder& req = request.Builder(); - req.PutFH(fHandle); + req.PutFH(fInfo.fHandle); req.SaveFH(); - req.PutFH(dir->fHandle); + req.PutFH(dir->fInfo.fHandle); req.Link(name); status_t result = request.Send(); @@ -244,7 +241,7 @@ Inode::Remove(const char* name, FileType type) Request request(serv); RequestBuilder& req = request.Builder(); - req.PutFH(fHandle); + req.PutFH(fInfo.fHandle); req.LookUp(name); AttrValue attr; attr.fAttribute = FATTR4_TYPE; @@ -255,7 +252,7 @@ Inode::Remove(const char* name, FileType type) else req.Nverify(&attr, 1); - req.PutFH(fHandle); + req.PutFH(fInfo.fHandle); req.Remove(name); status_t result = request.Send(); @@ -305,9 +302,9 @@ Inode::Rename(Inode* from, Inode* to, const char* fromName, const char* toName) Request request(serv); RequestBuilder& req = request.Builder(); - req.PutFH(from->fHandle); + req.PutFH(from->fInfo.fHandle); req.SaveFH(); - req.PutFH(to->fHandle); + req.PutFH(to->fInfo.fHandle); req.Rename(fromName, toName); status_t result = request.Send(); @@ -346,7 +343,7 @@ Inode::CreateLink(const char* name, const char* path, int mode) Request request(serv); RequestBuilder& req = request.Builder(); - req.PutFH(fHandle); + req.PutFH(fInfo.fHandle); AttrValue attr; attr.fAttribute = FATTR4_MODE; @@ -381,7 +378,7 @@ Inode::ReadLink(void* buffer, size_t* length) Request request(serv); RequestBuilder& req = request.Builder(); - req.PutFH(fHandle); + req.PutFH(fInfo.fHandle); req.ReadLink(); status_t result = request.Send(); @@ -412,7 +409,7 @@ Inode::Access(int mode) Request request(serv); RequestBuilder& req = request.Builder(); - req.PutFH(fHandle); + req.PutFH(fInfo.fHandle); req.Access(); status_t result = request.Send(); @@ -460,7 +457,7 @@ Inode::Stat(struct stat* st) Request request(serv); RequestBuilder& req = request.Builder(); - req.PutFH(fHandle); + req.PutFH(fInfo.fHandle); Attribute attr[] = { FATTR4_SIZE, FATTR4_MODE, FATTR4_NUMLINKS, FATTR4_TIME_ACCESS, FATTR4_TIME_CREATE, @@ -499,7 +496,7 @@ Inode::Stat(struct stat* st) } else { // Try to guess using ACCESS request request.Reset(); - request.Builder().PutFH(fHandle); + request.Builder().PutFH(fInfo.fHandle); request.Builder().Access(); result = request.Send(); if (result != B_OK) @@ -617,7 +614,7 @@ Inode::WriteStat(const struct stat* st, uint32 mask) Request request(serv); RequestBuilder& req = request.Builder(); - req.PutFH(fHandle); + req.PutFH(fInfo.fHandle); if ((mask & B_STAT_SIZE) != 0) req.SetAttr(cookie->fStateId, cookie->fStateSeq, attr, i); else @@ -690,7 +687,7 @@ Inode::TestLock(OpenFileCookie* cookie, struct flock* lock) Request request(serv); RequestBuilder& req = request.Builder(); - req.PutFH(fHandle); + req.PutFH(fInfo.fHandle); req.LockT(sGetLockType(lock->l_type, false), lock->l_start, lock->l_len, cookie); @@ -760,7 +757,7 @@ Inode::AcquireLock(OpenFileCookie* cookie, const struct flock* lock, Request request(serv); RequestBuilder& req = request.Builder(); - req.PutFH(fHandle); + req.PutFH(fInfo.fHandle); req.Lock(cookie, linfo); status_t result = request.Send(); @@ -829,7 +826,7 @@ Inode::ReleaseLock(OpenFileCookie* cookie, const struct flock* lock) Request request(serv); RequestBuilder& req = request.Builder(); - req.PutFH(fHandle); + req.PutFH(fInfo.fHandle); req.LockU(linfo); status_t result = request.Send(); @@ -874,7 +871,7 @@ Inode::ReleaseAllLocks(OpenFileCookie* cookie) Request request(serv); RequestBuilder& req = request.Builder(); - req.PutFH(fHandle); + req.PutFH(fInfo.fHandle); req.LockU(linfo); status_t result = request.Send(); @@ -1021,7 +1018,7 @@ Inode::_LookUpFilehandle() uint32 lookupCount = 0; sParsePath(req, &lookupCount, fFilesystem->Path()); - sParsePath(req, &lookupCount, fPath); + sParsePath(req, &lookupCount, fInfo.fPath); req.GetFH(); @@ -1029,7 +1026,7 @@ Inode::_LookUpFilehandle() AttrValue attr; attr.fAttribute = FATTR4_FILEID; attr.fFreePointer = false; - attr.fData.fValue64 = fFileId; + attr.fData.fValue64 = fInfo.fFileId; req.Verify(&attr, 1); } @@ -1043,7 +1040,7 @@ Inode::_LookUpFilehandle() for (uint32 i = 0; i < lookupCount; i++) reply.LookUp(); - result = reply.GetFH(&fHandle); + result = reply.GetFH(&fInfo.fHandle); if (result != B_OK) return result; diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h b/src/add-ons/kernel/file_systems/nfs4/Inode.h index 22a6f02036..155178200d 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -90,16 +90,10 @@ protected: static inline ino_t _FileIdToInoT(uint64 fileid); - uint64 fFileId; uint32 fType; - Filehandle fHandle; + FileInfo fInfo; Filesystem* fFilesystem; - - Filehandle fParentFH; - const char* fName; - - const char* fPath; }; @@ -117,7 +111,7 @@ Inode::_FileIdToInoT(uint64 fileid) inline ino_t Inode::ID() const { - return _FileIdToInoT(fFileId); + return _FileIdToInoT(fInfo.fFileId); } @@ -131,7 +125,7 @@ Inode::Type() const inline const char* Inode::Name() const { - return fName; + return fInfo.fName; } diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp b/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp index 290c56fb6a..c1a3bb13bb 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp @@ -24,7 +24,7 @@ Inode::CreateDir(const char* name, int mode) Request request(serv); RequestBuilder& req = request.Builder(); - req.PutFH(fHandle); + req.PutFH(fInfo.fHandle); AttrValue attr; attr.fAttribute = FATTR4_MODE; @@ -59,7 +59,7 @@ Inode::OpenDir(OpenDirCookie* cookie) Request request(serv); RequestBuilder& req = request.Builder(); - req.PutFH(fHandle); + req.PutFH(fInfo.fHandle); req.Access(); status_t result = request.Send(); @@ -99,7 +99,7 @@ Inode::_ReadDirOnce(DirEntry** dirents, uint32* count, OpenDirCookie* cookie, Request request(serv); RequestBuilder& req = request.Builder(); - req.PutFH(fHandle); + req.PutFH(fInfo.fHandle); Attribute attr[] = { FATTR4_FSID, FATTR4_FILEID }; req.ReadDir(*count, cookie->fCookie, cookie->fCookieVerf, attr, @@ -151,7 +151,7 @@ Inode::_ReadDirUp(struct dirent* de, uint32 pos, uint32 size) Request request(serv); RequestBuilder& req = request.Builder(); - req.PutFH(fHandle); + req.PutFH(fInfo.fHandle); req.LookUpUp(); req.GetFH(); @@ -214,7 +214,7 @@ Inode::ReadDir(void* _buffer, uint32 size, uint32* _count, if (cookie->fCookie == 0 && cookie->fCookieVerf == 2 && count < *_count) { struct dirent* de = reinterpret_cast(buffer + pos); - _FillDirEntry(de, fFileId, ".", pos, size); + _FillDirEntry(de, fInfo.fFileId, ".", pos, size); pos += de->d_reclen; count++; @@ -224,10 +224,10 @@ Inode::ReadDir(void* _buffer, uint32 size, uint32* _count, if (cookie->fCookie == 0 && cookie->fCookieVerf == 1 && count < *_count) { struct dirent* de = reinterpret_cast(buffer + pos); - if (strcmp(fName, "/")) + if (strcmp(fInfo.fName, "/")) _ReadDirUp(de, pos, size); else - _FillDirEntry(de, _FileIdToInoT(fFileId), "..", pos, size); + _FillDirEntry(de, _FileIdToInoT(fInfo.fFileId), "..", pos, size); pos += de->d_reclen; count++; diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp index 362db476c5..199dabe9a1 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp @@ -75,7 +75,7 @@ Inode::Create(const char* name, int mode, int perms, OpenFileCookie* cookie, cookie->fOwnerId = atomic_add64(&cookie->fLastOwnerId, 1); - req.PutFH(fHandle); + req.PutFH(fInfo.fHandle); AttrValue cattr[2]; uint32 i = 0; @@ -130,13 +130,13 @@ Inode::Create(const char* name, int mode, int perms, OpenFileCookie* cookie, FileInfo fi; fi.fFileId = fileId; - fi.fFH = fh; - fi.fParent = fHandle; + fi.fHandle = fh; + fi.fParent = fInfo.fHandle; fi.fName = strdup(name); char* path = reinterpret_cast(malloc(strlen(name) + 2 + - strlen(fPath))); - strcpy(path, fPath); + strlen(fInfo.fPath))); + strcpy(path, fInfo.fPath); strcat(path, "/"); strcat(path, name); fi.fPath = path; @@ -144,7 +144,7 @@ Inode::Create(const char* name, int mode, int perms, OpenFileCookie* cookie, fFilesystem->InoIdMap()->AddEntry(fi, *id); cookie->fFilesystem = fFilesystem; - cookie->fHandle = fh; + cookie->fInfo = fi; break; } while (true); @@ -165,7 +165,7 @@ Inode::Open(int mode, OpenFileCookie* cookie) status_t result; cookie->fFilesystem = fFilesystem; - cookie->fHandle = fHandle; + cookie->fInfo = fInfo; cookie->fMode = mode; cookie->fSequence = 0; cookie->fLocks = NULL; @@ -182,36 +182,36 @@ Inode::Open(int mode, OpenFileCookie* cookie) // 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(fParentFH); - req.LookUp(fName); + req.PutFH(fInfo.fParent); + req.LookUp(fInfo.fName); AttrValue attr; attr.fAttribute = FATTR4_FILEID; attr.fFreePointer = false; - attr.fData.fValue64 = fFileId; + attr.fData.fValue64 = fInfo.fFileId; req.Verify(&attr, 1); } else if (fFilesystem->ExpireType() == FH4_PERSISTENT) { - req.PutFH(fParentFH); - req.LookUp(fName); + req.PutFH(fInfo.fParent); + req.LookUp(fInfo.fName); AttrValue attr; attr.fAttribute = FATTR4_FILEHANDLE; attr.fFreePointer = true; - attr.fData.fPointer = malloc(sizeof(fHandle)); - memcpy(attr.fData.fPointer, &fHandle, sizeof(fHandle)); + attr.fData.fPointer = malloc(sizeof(fInfo.fHandle)); + memcpy(attr.fData.fPointer, &fInfo.fHandle, sizeof(fInfo.fHandle)); req.Verify(&attr, 1); } - req.PutFH(fParentFH); + 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, fName, &attr, - 1, false); + 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, fName); + cookie->fClientId, OPEN4_NOCREATE, cookie->fOwnerId, fInfo.fName); result = request.Send(); if (result != B_OK) @@ -248,7 +248,7 @@ Inode::Open(int mode, OpenFileCookie* cookie) fFilesystem->AddOpenFile(cookie); if (confirm) - return _ConfirmOpen(fHandle, cookie); + return _ConfirmOpen(fInfo.fHandle, cookie); else return B_OK; } @@ -264,7 +264,7 @@ Inode::Close(OpenFileCookie* cookie) Request request(serv); RequestBuilder& req = request.Builder(); - req.PutFH(fHandle); + req.PutFH(fInfo.fHandle); req.Close(cookie->fSequence++, cookie->fStateId, cookie->fStateSeq); @@ -302,7 +302,7 @@ Inode::Read(OpenFileCookie* cookie, off_t pos, void* buffer, size_t* _length) Request request(serv); RequestBuilder& req = request.Builder(); - req.PutFH(fHandle); + req.PutFH(fInfo.fHandle); req.Read(cookie->fStateId, cookie->fStateSeq, pos + size, *_length - size); @@ -358,7 +358,7 @@ Inode::Write(OpenFileCookie* cookie, off_t pos, const void* _buffer, pos = fileSize; } - req.PutFH(fHandle); + req.PutFH(fInfo.fHandle); if ((cookie->fMode & O_APPEND) == O_APPEND) { AttrValue attr; attr.fAttribute = FATTR4_SIZE; diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp index 17908e7fa3..49886ef592 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp @@ -77,7 +77,7 @@ NFS4Server::_ReclaimOpen(OpenFileCookie* cookie) Request request(fServer); RequestBuilder& req = request.Builder(); - req.PutFH(cookie->fHandle); + req.PutFH(cookie->fInfo.fHandle); req.Open(CLAIM_PREVIOUS, cookie->fSequence++, sModeToAccess(cookie->fMode), cookie->fClientId, OPEN4_NOCREATE, cookie->fOwnerId, NULL); @@ -97,7 +97,7 @@ NFS4Server::_ReclaimOpen(OpenFileCookie* cookie) if (confirm) { request.Reset(); - req.PutFH(cookie->fHandle); + req.PutFH(cookie->fInfo.fHandle); req.OpenConfirm(cookie->fSequence++, cookie->fStateId, cookie->fStateSeq); @@ -131,7 +131,7 @@ NFS4Server::_ReclaimLocks(OpenFileCookie* cookie) Request request(fServer); RequestBuilder& req = request.Builder(); - req.PutFH(cookie->fHandle); + req.PutFH(cookie->fInfo.fHandle); req.Lock(cookie, linfo, true); status_t result = request.Send(); diff --git a/src/add-ons/kernel/file_systems/nfs4/RootInode.cpp b/src/add-ons/kernel/file_systems/nfs4/RootInode.cpp index 073dee4346..4b8ed2eb35 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RootInode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RootInode.cpp @@ -22,7 +22,7 @@ RootInode::ReadInfo(struct fs_info* info) Request request(serv); RequestBuilder& req = request.Builder(); - req.PutFH(fHandle); + req.PutFH(fInfo.fHandle); Attribute attr[] = { FATTR4_FILES_FREE, FATTR4_FILES_TOTAL, FATTR4_MAXREAD, FATTR4_MAXWRITE, FATTR4_SPACE_FREE, FATTR4_SPACE_TOTAL }; @@ -87,7 +87,7 @@ RootInode::ReadInfo(struct fs_info* info) } while (true); info->flags = 0; - strncpy(info->volume_name, fName, B_FILE_NAME_LENGTH); + strncpy(info->volume_name, fInfo.fName, B_FILE_NAME_LENGTH); return B_OK; } @@ -101,7 +101,7 @@ RootInode::ProbeMigration() Request request(serv); RequestBuilder& req = request.Builder(); - req.PutFH(fHandle); + req.PutFH(fInfo.fHandle); req.Access(); status_t result = request.Send(); @@ -130,7 +130,7 @@ RootInode::GetLocations(AttrValue** attrv) Request request(serv); RequestBuilder& req = request.Builder(); - req.PutFH(fHandle); + req.PutFH(fInfo.fHandle); Attribute attr[] = { FATTR4_FS_LOCATIONS }; req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); From fed1e3e967e6f1e49a6ed544e8f269a7c56fe811 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Tue, 3 Jul 2012 01:40:17 +0200 Subject: [PATCH 115/252] nfs4: Use FileId in lock owner generation --- src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp index 1f37a9045a..8f67dbc2d8 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp @@ -156,7 +156,7 @@ RequestBuilder::_GenerateLockOwner(XDR::WriteStream& stream, uint64 lockOwner[2]; lockOwner[0] = owner->fOwner; - lockOwner[1] = cookie->fOwnerId; + lockOwner[1] = cookie->fInfo.fFileId; stream.AddOpaque(lockOwner, sizeof(lockOwner)); } From 9b7f2d1b24a8f67aacc5f80434f9480a10f88e25 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Tue, 3 Jul 2012 02:01:30 +0200 Subject: [PATCH 116/252] nfs4: Move file handle recovery code out of Inode class --- .../kernel/file_systems/nfs4/FileInfo.cpp | 90 +++++++++++++++++++ .../nfs4/{Filehandle.h => FileInfo.h} | 10 ++- .../kernel/file_systems/nfs4/Inode.cpp | 80 ++--------------- src/add-ons/kernel/file_systems/nfs4/Inode.h | 1 - .../kernel/file_systems/nfs4/InodeIdMap.h | 2 +- src/add-ons/kernel/file_systems/nfs4/Jamfile | 1 + .../kernel/file_systems/nfs4/NFS4Defs.h | 1 - .../file_systems/nfs4/ReplyInterpreter.h | 1 + .../kernel/file_systems/nfs4/RequestBuilder.h | 1 + 9 files changed, 106 insertions(+), 81 deletions(-) create mode 100644 src/add-ons/kernel/file_systems/nfs4/FileInfo.cpp rename src/add-ons/kernel/file_systems/nfs4/{Filehandle.h => FileInfo.h} (94%) diff --git a/src/add-ons/kernel/file_systems/nfs4/FileInfo.cpp b/src/add-ons/kernel/file_systems/nfs4/FileInfo.cpp new file mode 100644 index 0000000000..1ec4daa316 --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/FileInfo.cpp @@ -0,0 +1,90 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ + + +#include "FileInfo.h" + +#include "Filesystem.h" +#include "Request.h" + + +static status_t +sParsePath(RequestBuilder& req, uint32* count, const char* _path) +{ + char* path = strdup(_path); + char* pathStart = path; + char* pathEnd; + while (pathStart != NULL) { + pathEnd = strpbrk(pathStart, "/"); + if (pathEnd != NULL) + *pathEnd = '\0'; + + req.LookUp(pathStart); + + if (pathEnd != NULL && pathEnd[1] != '\0') + pathStart = pathEnd + 1; + else + pathStart = NULL; + + (*count)++; + } + free(path); + + return B_OK; +} + + +status_t +FileInfo::UpdateFileHandles(Filesystem* fs) +{ + Request request(fs->Server()); + RequestBuilder& req = request.Builder(); + + req.PutRootFH(); + + uint32 lookupCount = 0; + + sParsePath(req, &lookupCount, fs->Path()); + sParsePath(req, &lookupCount, fPath); + + if (fs->IsAttrSupported(FATTR4_FILEID)) { + AttrValue attr; + attr.fAttribute = FATTR4_FILEID; + attr.fFreePointer = false; + attr.fData.fValue64 = fFileId; + req.Verify(&attr, 1); + } + + req.GetFH(); + req.LookUpUp(); + req.GetFH(); + + status_t result = request.Send(); + if (result != B_OK) + return result; + + ReplyInterpreter& reply = request.Reply(); + + reply.PutRootFH(); + for (uint32 i = 0; i < lookupCount; i++) + reply.LookUp(); + + if (fs->IsAttrSupported(FATTR4_FILEID)) { + result = reply.Verify(); + if (result != B_OK) + return result; + } + + reply.GetFH(&fHandle); + if (reply.LookUpUp() == B_ENTRY_NOT_FOUND) { + fParent = fHandle; + return B_OK; + } else + return reply.GetFH(&fParent); +} + diff --git a/src/add-ons/kernel/file_systems/nfs4/Filehandle.h b/src/add-ons/kernel/file_systems/nfs4/FileInfo.h similarity index 94% rename from src/add-ons/kernel/file_systems/nfs4/Filehandle.h rename to src/add-ons/kernel/file_systems/nfs4/FileInfo.h index 423a72149d..a250262afe 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Filehandle.h +++ b/src/add-ons/kernel/file_systems/nfs4/FileInfo.h @@ -5,8 +5,8 @@ * Authors: * Paweł Dziepak, pdziepak@quarnos.org */ -#ifndef FILEHANDLE_H -#define FILEHANDLE_H +#ifndef FILEINFO_H +#define FILEINFO_H #include @@ -27,6 +27,8 @@ struct Filehandle { }; +class Filesystem; + // Complete information needed to identify a file in any situation. // Unfortunately just a filehandle is not enough even when they are persistent // since OPEN requires both parent filehandle and file name (just like LOOKUP). @@ -42,6 +44,8 @@ struct FileInfo { inline ~FileInfo(); inline FileInfo(const FileInfo& fi); inline FileInfo& operator=(const FileInfo& fi); + + status_t UpdateFileHandles(Filesystem* fs); }; struct FilesystemId { @@ -140,5 +144,5 @@ FilesystemId::operator!=(const FilesystemId& fsid) const } -#endif // FILEHANDLE_H +#endif // FILEHINFO_H diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index ea5cc288ac..ccecb6ff36 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -210,8 +210,8 @@ Inode::Link(Inode* dir, const char* name) // filehandle has expired if (reply.NFS4Error() == NFS4ERR_FHEXPIRED) { - _LookUpFilehandle(); - dir->_LookUpFilehandle(); + fInfo.UpdateFileHandles(fFilesystem); + dir->fInfo.UpdateFileHandles(dir->fFilesystem); continue; } @@ -315,8 +315,8 @@ Inode::Rename(Inode* from, Inode* to, const char* fromName, const char* toName) // filehandle has expired if (reply.NFS4Error() == NFS4ERR_FHEXPIRED) { - from->_LookUpFilehandle(); - to->_LookUpFilehandle(); + from->fInfo.UpdateFileHandles(from->fFilesystem); + to->fInfo.UpdateFileHandles(to->fFilesystem); continue; } @@ -956,7 +956,7 @@ Inode::_HandleErrors(uint32 nfs4Error, RPC::Server* serv, // filehandle has expired case NFS4ERR_FHEXPIRED: - if (_LookUpFilehandle() == B_OK) + if (fInfo.UpdateFileHandles(fFilesystem) == B_OK) return true; else return false; @@ -980,73 +980,3 @@ Inode::_HandleErrors(uint32 nfs4Error, RPC::Server* serv, } } - -static status_t -sParsePath(RequestBuilder& req, uint32* count, const char* _path) -{ - char* path = strdup(_path); - char* pathStart = path; - char* pathEnd; - while (pathStart != NULL) { - pathEnd = strpbrk(pathStart, "/"); - if (pathEnd != NULL) - *pathEnd = '\0'; - - req.LookUp(pathStart); - - if (pathEnd != NULL && pathEnd[1] != '\0') - pathStart = pathEnd + 1; - else - pathStart = NULL; - - (*count)++; - } - free(path); - - return B_OK; -} - - -status_t -Inode::_LookUpFilehandle() -{ - Request request(fFilesystem->Server()); - RequestBuilder& req = request.Builder(); - - req.PutRootFH(); - - uint32 lookupCount = 0; - - sParsePath(req, &lookupCount, fFilesystem->Path()); - sParsePath(req, &lookupCount, fInfo.fPath); - - req.GetFH(); - - if (fFilesystem->IsAttrSupported(FATTR4_FILEID)) { - AttrValue attr; - attr.fAttribute = FATTR4_FILEID; - attr.fFreePointer = false; - attr.fData.fValue64 = fInfo.fFileId; - req.Verify(&attr, 1); - } - - status_t result = request.Send(); - if (result != B_OK) - return result; - - ReplyInterpreter& reply = request.Reply(); - - reply.PutRootFH(); - for (uint32 i = 0; i < lookupCount; i++) - reply.LookUp(); - - result = reply.GetFH(&fInfo.fHandle); - if (result != B_OK) - return result; - - if (fFilesystem->IsAttrSupported(FATTR4_FILEID)) - return reply.Verify(); - 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 155178200d..76445e709c 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -74,7 +74,6 @@ protected: bool _HandleErrors(uint32 nfs4Error, RPC::Server* serv, OpenFileCookie* cookie = NULL); - status_t _LookUpFilehandle(); status_t _ConfirmOpen(const Filehandle& fh, OpenFileCookie* cookie); diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeIdMap.h b/src/add-ons/kernel/file_systems/nfs4/InodeIdMap.h index 6cde1f39eb..63ec1b07b3 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeIdMap.h +++ b/src/add-ons/kernel/file_systems/nfs4/InodeIdMap.h @@ -14,7 +14,7 @@ #include #include -#include "Filehandle.h" +#include "FileInfo.h" class InodeIdMap { diff --git a/src/add-ons/kernel/file_systems/nfs4/Jamfile b/src/add-ons/kernel/file_systems/nfs4/Jamfile index 57060a135b..eb8e5e820a 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Jamfile +++ b/src/add-ons/kernel/file_systems/nfs4/Jamfile @@ -6,6 +6,7 @@ UsePrivateHeaders shared ; KernelAddon nfs4 : Cookie.cpp Connection.cpp + FileInfo.cpp Filesystem.cpp Inode.cpp InodeDir.cpp diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h index 853c783d8a..31e82c2670 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h @@ -14,7 +14,6 @@ #include -#include "Filehandle.h" enum Procedure { ProcNull = 0, diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h index 0595a8bbbf..8e99e9eb7b 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h @@ -11,6 +11,7 @@ #include +#include "FileInfo.h" #include "NFS4Defs.h" #include "RPCReply.h" diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h index 0143a9a65d..f59aac7940 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h @@ -11,6 +11,7 @@ #include +#include "FileInfo.h" #include "NFS4Defs.h" #include "ReplyInterpreter.h" #include "RPCCall.h" From b2cea80ce5328c07e9f5c42c72213c186737aea5 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Tue, 3 Jul 2012 19:17:37 +0200 Subject: [PATCH 117/252] nfs4: Add id mapper --- build/jam/HaikuImage | 2 +- .../kernel/file_systems/nfs4/IdMap.cpp | 190 +++++++++++++ src/add-ons/kernel/file_systems/nfs4/IdMap.h | 47 ++++ .../kernel/file_systems/nfs4/Inode.cpp | 42 ++- .../kernel/file_systems/nfs4/InodeDir.cpp | 24 +- .../kernel/file_systems/nfs4/InodeRegular.cpp | 17 +- src/add-ons/kernel/file_systems/nfs4/Jamfile | 4 + .../file_systems/nfs4/ReplyInterpreter.cpp | 14 + .../file_systems/nfs4/RequestBuilder.cpp | 10 + src/add-ons/kernel/file_systems/nfs4/XDR.cpp | 2 +- src/add-ons/kernel/file_systems/nfs4/XDR.h | 2 +- .../file_systems/nfs4/idmapper/IdMapper.cpp | 266 ++++++++++++++++++ .../file_systems/nfs4/idmapper/IdMapper.h | 26 ++ .../kernel/file_systems/nfs4/idmapper/Jamfile | 13 + .../nfs4/idmapper/nfs4_idmapper_server.rdef | 20 ++ .../file_systems/nfs4/kernel_interface.cpp | 9 + 16 files changed, 670 insertions(+), 18 deletions(-) create mode 100644 src/add-ons/kernel/file_systems/nfs4/IdMap.cpp create mode 100644 src/add-ons/kernel/file_systems/nfs4/IdMap.h create mode 100644 src/add-ons/kernel/file_systems/nfs4/idmapper/IdMapper.cpp create mode 100644 src/add-ons/kernel/file_systems/nfs4/idmapper/IdMapper.h create mode 100644 src/add-ons/kernel/file_systems/nfs4/idmapper/Jamfile create mode 100644 src/add-ons/kernel/file_systems/nfs4/idmapper/nfs4_idmapper_server.rdef diff --git a/build/jam/HaikuImage b/build/jam/HaikuImage index 0d2714b10b..3c7bb0ec21 100644 --- a/build/jam/HaikuImage +++ b/build/jam/HaikuImage @@ -106,7 +106,7 @@ PRIVATE_SYSTEM_LIBS = SYSTEM_SERVERS = app_server cddb_daemon debug_server input_server mail_daemon media_addon_server media_server midi_server mount_server net_server notification_server power_daemon print_server print_addon_server registrar syslog_daemon - dns_resolver_server + dns_resolver_server nfs4_idmapper_server ; SYSTEM_NETWORK_DEVICES = ethernet loopback ; diff --git a/src/add-ons/kernel/file_systems/nfs4/IdMap.cpp b/src/add-ons/kernel/file_systems/nfs4/IdMap.cpp new file mode 100644 index 0000000000..37d755947b --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/IdMap.cpp @@ -0,0 +1,190 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ + + +#include "IdMap.h" + +#include +#include +#include + +#include "idmapper/IdMapper.h" + + +IdMap* gIdMapper = NULL; + + +IdMap::IdMap() +{ + mutex_init(&fLock, NULL); + _Repair(); +} + + +IdMap::~IdMap() +{ + delete_port(fRequestPort); + delete_port(fReplyPort); + mutex_destroy(&fLock); +} + + +uid_t +IdMap::GetUserId(const char* owner) +{ + return _GetValue(owner, MsgNameToUID); +} + + +gid_t +IdMap::GetGroupId(const char* ownerGroup) +{ + return _GetValue(ownerGroup, MsgNameToGID); +} + + +char* +IdMap::GetOwner(uid_t user) +{ + return reinterpret_cast(_GetBuffer(user, MsgUIDToName)); +} + + +char* +IdMap::GetOwnerGroup(gid_t group) +{ + return reinterpret_cast(_GetBuffer(group, MsgGIDToName)); +} + + +template +T +IdMap::_GetValue(const char* buffer, int32 code) +{ + MutexLocker _(fLock); + do { + status_t result = write_port(fRequestPort, MsgNameToUID, buffer, + strlen(buffer) + 1); + if (result != B_OK) { + if (_Repair() != B_OK) + return 0; + else + continue; + } + + int32 code; + T value; + result = read_port(fReplyPort, &code, &value, sizeof(T)); + if (result < B_OK) { + if (_Repair() != B_OK) + return 0; + else + continue; + } + + if (code != MsgReply) + return 0; + else + return value; + } while (true); +} + + +template +void* +IdMap::_GetBuffer(T value, int32 code) +{ + MutexLocker _(fLock); + do { + status_t result = write_port(fRequestPort, code, &value, sizeof(value)); + if (result != B_OK) { + if (_Repair() != B_OK) + return NULL; + else + continue; + } + + ssize_t size = port_buffer_size(fReplyPort); + if (size < B_OK) { + if (_Repair() != B_OK) + return NULL; + else + continue; + } + + int32 code; + void* buffer = malloc(size); + if (buffer == NULL) + return NULL; + + result = read_port(fReplyPort, &code, buffer, size); + if (result < B_OK) { + free(buffer); + + if (_Repair() != B_OK) + return 0; + else + continue; + } + + if (code != MsgReply) { + free(buffer); + return NULL; + } else + return buffer; + } while (true); +} + + +status_t +IdMap::_Repair() +{ + status_t result = B_OK; + + fRequestPort = create_port(1, kRequestPortName); + if (fRequestPort < B_OK) + return fRequestPort; + + fReplyPort = create_port(1, kReplyPortName); + if (fReplyPort < B_OK) { + delete_port(fRequestPort); + return fReplyPort; + } + + char path[256]; + if (find_directory(B_SYSTEM_SERVERS_DIRECTORY, static_cast(-1), + false, path, sizeof(path)) != B_OK) { + delete_port(fReplyPort); + delete_port(fRequestPort); + return B_NAME_NOT_FOUND; + } + strlcat(path, "/nfs4_idmapper_server", sizeof(path)); + + const char* args[] = { path, NULL }; + thread_id thread = load_image_etc(1, args, NULL, B_NORMAL_PRIORITY, + B_SYSTEM_TEAM, 0); + if (thread < B_OK) { + delete_port(fReplyPort); + delete_port(fRequestPort); + return thread; + } + + set_port_owner(fRequestPort, thread); + set_port_owner(fReplyPort, thread); + + result = resume_thread(thread); + if (result != B_OK) { + kill_thread(thread); + delete_port(fReplyPort); + delete_port(fRequestPort); + return result; + } + + return B_OK; +} + diff --git a/src/add-ons/kernel/file_systems/nfs4/IdMap.h b/src/add-ons/kernel/file_systems/nfs4/IdMap.h new file mode 100644 index 0000000000..266bef6366 --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/IdMap.h @@ -0,0 +1,47 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ +#ifndef IDMAP_H +#define IDMAP_H + + +#include +#include +#include + + +class IdMap { +public: + IdMap(); + ~IdMap(); + + uid_t GetUserId(const char* owner); + gid_t GetGroupId(const char* ownerGroup); + + char* GetOwner(uid_t user); + char* GetOwnerGroup(gid_t group); + +private: + status_t _Repair(); + + template + void* _GetBuffer(T value, int32 code); + + template + T _GetValue(const char* buffer, int32 code); + + mutex fLock; + + port_id fRequestPort; + port_id fReplyPort; +}; + +extern IdMap* gIdMapper; + + +#endif // IDMAP_H + diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index ccecb6ff36..836962bdac 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -13,6 +13,7 @@ #include +#include "IdMap.h" #include "Request.h" #include "RootInode.h" @@ -345,11 +346,24 @@ Inode::CreateLink(const char* name, const char* path, int mode) req.PutFH(fInfo.fHandle); - AttrValue attr; - attr.fAttribute = FATTR4_MODE; - attr.fFreePointer = false; - attr.fData.fValue32 = mode; - req.Create(NF4LNK, name, &attr, 1, path); + uint32 i = 0; + AttrValue cattr[3]; + cattr[i].fAttribute = FATTR4_MODE; + cattr[i].fFreePointer = false; + cattr[i].fData.fValue32 = mode; + i++; + + cattr[i].fAttribute = FATTR4_OWNER; + cattr[i].fFreePointer = true; + cattr[i].fData.fPointer = gIdMapper->GetOwner(getuid()); + i++; + + cattr[i].fAttribute = FATTR4_OWNER_GROUP; + cattr[i].fFreePointer = true; + cattr[i].fData.fPointer = gIdMapper->GetOwnerGroup(getgid()); + i++; + + req.Create(NF4LNK, name, cattr, i, path); status_t result = request.Send(); if (result != B_OK) @@ -460,6 +474,7 @@ Inode::Stat(struct stat* st) req.PutFH(fInfo.fHandle); Attribute attr[] = { FATTR4_SIZE, FATTR4_MODE, FATTR4_NUMLINKS, + FATTR4_OWNER, FATTR4_OWNER_GROUP, FATTR4_TIME_ACCESS, FATTR4_TIME_CREATE, FATTR4_TIME_METADATA, FATTR4_TIME_MODIFY }; req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); @@ -526,6 +541,20 @@ Inode::Stat(struct stat* st) } else st->st_nlink = 1; + if (count >= next && values[next].fAttribute == FATTR4_OWNER) { + char* owner = reinterpret_cast(values[next].fData.fPointer); + st->st_uid = gIdMapper->GetUserId(owner); + next++; + } else + st->st_uid = 0; + + if (count >= next && values[next].fAttribute == FATTR4_OWNER_GROUP) { + char* group = reinterpret_cast(values[next].fData.fPointer); + st->st_gid = gIdMapper->GetGroupId(group); + next++; + } else + st->st_gid = 0; + if (count >= next && values[next].fAttribute == FATTR4_TIME_ACCESS) { memcpy(&st->st_atim, values[next].fData.fPointer, sizeof(timespec)); next++; @@ -551,9 +580,6 @@ Inode::Stat(struct stat* st) } else memset(&st->st_mtim, 0, sizeof(timespec)); - st->st_uid = 0; - st->st_gid = 0; - delete[] values; return B_OK; } while (true); diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp b/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp index c1a3bb13bb..d41ddca6f3 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp @@ -12,6 +12,7 @@ #include #include +#include "IdMap.h" #include "Request.h" #include "RootInode.h" @@ -26,11 +27,24 @@ Inode::CreateDir(const char* name, int mode) req.PutFH(fInfo.fHandle); - AttrValue attr; - attr.fAttribute = FATTR4_MODE; - attr.fFreePointer = false; - attr.fData.fValue32 = mode; - req.Create(NF4DIR, name, &attr, 1); + uint32 i = 0; + AttrValue cattr[3]; + cattr[i].fAttribute = FATTR4_MODE; + cattr[i].fFreePointer = false; + cattr[i].fData.fValue32 = mode; + i++; + + cattr[i].fAttribute = FATTR4_OWNER; + cattr[i].fFreePointer = true; + cattr[i].fData.fPointer = gIdMapper->GetOwner(getuid()); + i++; + + cattr[i].fAttribute = FATTR4_OWNER_GROUP; + cattr[i].fFreePointer = true; + cattr[i].fData.fPointer = gIdMapper->GetOwnerGroup(getgid()); + i++; + + req.Create(NF4DIR, name, cattr, i); status_t result = request.Send(); if (result != B_OK) diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp index 199dabe9a1..b0e92cbbf1 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp @@ -13,6 +13,7 @@ #include +#include "IdMap.h" #include "Request.h" @@ -77,7 +78,7 @@ Inode::Create(const char* name, int mode, int perms, OpenFileCookie* cookie, req.PutFH(fInfo.fHandle); - AttrValue cattr[2]; + AttrValue cattr[4]; uint32 i = 0; if ((mode & O_TRUNC) == O_TRUNC) { cattr[i].fAttribute = FATTR4_SIZE; @@ -88,9 +89,21 @@ Inode::Create(const char* name, int mode, int perms, OpenFileCookie* cookie, cattr[i].fAttribute = FATTR4_MODE; cattr[i].fFreePointer = false; cattr[i].fData.fValue32 = perms; + i++; + + cattr[i].fAttribute = FATTR4_OWNER; + cattr[i].fFreePointer = true; + cattr[i].fData.fPointer = gIdMapper->GetOwner(getuid()); + i++; + + cattr[i].fAttribute = FATTR4_OWNER_GROUP; + 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 + 1, (mode & O_EXCL) == O_EXCL); + i, (mode & O_EXCL) == O_EXCL); req.GetFH(); diff --git a/src/add-ons/kernel/file_systems/nfs4/Jamfile b/src/add-ons/kernel/file_systems/nfs4/Jamfile index eb8e5e820a..822bf4147e 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Jamfile +++ b/src/add-ons/kernel/file_systems/nfs4/Jamfile @@ -8,6 +8,7 @@ KernelAddon nfs4 : Connection.cpp FileInfo.cpp Filesystem.cpp + IdMap.cpp Inode.cpp InodeDir.cpp InodeRegular.cpp @@ -23,3 +24,6 @@ KernelAddon nfs4 : RPCServer.cpp XDR.cpp ; + +SubInclude HAIKU_TOP src add-ons kernel file_systems nfs4 idmapper ; + diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp index c5c97c84c5..43755b2687 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp @@ -614,6 +614,20 @@ ReplyInterpreter::_DecodeAttrs(XDR::ReadStream& str, AttrValue** attrs, current++; } + if (sIsAttrSet(FATTR4_OWNER, bitmap, bcount)) { + values[current].fAttribute = FATTR4_OWNER; + values[current].fFreePointer = true; + values[current].fData.fPointer = stream.GetString(); + current++; + } + + if (sIsAttrSet(FATTR4_OWNER_GROUP, bitmap, bcount)) { + values[current].fAttribute = FATTR4_OWNER_GROUP; + values[current].fFreePointer = true; + values[current].fData.fPointer = stream.GetString(); + current++; + } + if (sIsAttrSet(FATTR4_SPACE_FREE, bitmap, bcount)) { values[current].fAttribute = FATTR4_SPACE_FREE; values[current].fData.fValue64 = stream.GetUHyper(); diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp index 8f67dbc2d8..81cade2607 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp @@ -776,6 +776,16 @@ RequestBuilder::_EncodeAttrs(XDR::WriteStream& stream, AttrValue* attr, i++; } + if (i < count && attr[i].fAttribute == FATTR4_OWNER) { + str.AddString(reinterpret_cast(attr[i].fData.fPointer)); + i++; + } + + if (i < count && attr[i].fAttribute == FATTR4_OWNER_GROUP) { + str.AddString(reinterpret_cast(attr[i].fData.fPointer)); + i++; + } + if (i < count && attr[i].fAttribute == FATTR4_TIME_ACCESS_SET) { str.AddInt(1); // SET_TO_CLIENT_TIME4 diff --git a/src/add-ons/kernel/file_systems/nfs4/XDR.cpp b/src/add-ons/kernel/file_systems/nfs4/XDR.cpp index 423d444e0f..9cc116d393 100644 --- a/src/add-ons/kernel/file_systems/nfs4/XDR.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/XDR.cpp @@ -115,7 +115,7 @@ ReadStream::GetUHyper() } -const char* +char* ReadStream::GetString() { if (_PositionToSize() >= fSize) { diff --git a/src/add-ons/kernel/file_systems/nfs4/XDR.h b/src/add-ons/kernel/file_systems/nfs4/XDR.h index 5d5300e321..f52ae0f9e9 100644 --- a/src/add-ons/kernel/file_systems/nfs4/XDR.h +++ b/src/add-ons/kernel/file_systems/nfs4/XDR.h @@ -48,7 +48,7 @@ public: inline bool GetBoolean(); - const char* GetString(); + char* GetString(); const void* GetOpaque(uint32* size); diff --git a/src/add-ons/kernel/file_systems/nfs4/idmapper/IdMapper.cpp b/src/add-ons/kernel/file_systems/nfs4/idmapper/IdMapper.cpp new file mode 100644 index 0000000000..a0d6c490c8 --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/idmapper/IdMapper.cpp @@ -0,0 +1,266 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ + + +#include "IdMapper.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + +port_id gRequestPort; +port_id gReplyPort; + +const char* kNobodyName = "nobody"; +uid_t gNobodyId; + +const char* kNogroupName = "nobody"; +uid_t gNogroupId; + +const char* gDomainName = "localdomain"; + + +status_t +SendError(status_t error) +{ + return write_port(gReplyPort, MsgError, &error, sizeof(error)); +} + + +status_t +MatchDomain(char* name) +{ + char* domain = strchr(name, '@'); + if (domain == NULL) + return B_MISMATCHED_VALUES; + + if (strcmp(domain + 1, gDomainName) != 0) + return B_BAD_VALUE; + + *domain = '\0'; + + return B_OK; +} + + +char* +AddDomain(const char* name) +{ + uint32 fullLength = strlen(name) + strlen(gDomainName) + 2; + char* fullName = reinterpret_cast(malloc(fullLength)); + + strcpy(fullName, name); + strcat(fullName, "@"); + strcat(fullName, gDomainName); + + return fullName; +} + + +status_t +NameToUID(void* buffer) +{ + char* userName = reinterpret_cast(buffer); + + struct passwd* userInfo = NULL; + + if (MatchDomain(userName) == B_OK) + userInfo = getpwnam(userName); + + if (userInfo == NULL) + return write_port(gReplyPort, MsgReply, &gNobodyId, sizeof(gNobodyId)); + + return write_port(gReplyPort, MsgReply, &userInfo->pw_uid, sizeof(uid_t)); +} + + +status_t +UIDToName(void* buffer) +{ + uid_t userId = *reinterpret_cast(buffer); + + const char* fullName = kNobodyName; + + struct passwd* userInfo = getpwuid(userId); + if (userInfo != NULL) { + const char* name = userInfo->pw_name; + fullName = AddDomain(name); + } + + status_t result = write_port(gReplyPort, MsgReply, fullName, + strlen(fullName) + 1); + free(const_cast(fullName)); + + return result; +} + + +status_t +NameToGID(void* buffer) +{ + char* groupName = reinterpret_cast(buffer); + + struct group* groupInfo = NULL; + + if (MatchDomain(groupName) == B_OK) + groupInfo = getgrnam(groupName); + + if (groupInfo == NULL) { + return write_port(gReplyPort, MsgReply, &gNogroupId, + sizeof(gNogroupId)); + } + + return write_port(gReplyPort, MsgReply, &groupInfo->gr_gid, sizeof(gid_t)); +} + + +status_t +GIDToName(void* buffer) +{ + gid_t groupId = *reinterpret_cast(buffer); + + const char* fullName = kNogroupName; + + struct group* groupInfo = getgrgid(groupId); + if (groupInfo != NULL) { + const char* name = groupInfo->gr_name; + fullName = AddDomain(name); + } + + status_t result = write_port(gReplyPort, MsgReply, fullName, + strlen(fullName) + 1); + free(const_cast(fullName)); + + return result; +} + + +status_t +ParseRequest(int32 code, void* buffer) +{ + switch (code) { + case MsgNameToUID: + return NameToUID(buffer); + + case MsgUIDToName: + return UIDToName(buffer); + + case MsgNameToGID: + return NameToGID(buffer); + + case MsgGIDToName: + return GIDToName(buffer); + + default: + return SendError(B_BAD_VALUE); + } +} + + +status_t +MainLoop() +{ + do { + ssize_t size = port_buffer_size(gRequestPort); + if (size < B_OK) + return 0; + + void* buffer = malloc(size); + if (buffer == NULL) + return B_NO_MEMORY; + + int32 code; + status_t result = read_port(gRequestPort, &code, buffer, size); + if (size < B_OK) { + free(buffer); + return 0; + } + + result = ParseRequest(code, buffer); + free(buffer); + + if (result == B_BAD_PORT_ID) + return 0; + + } while (true); +} + + +status_t +ReadSettings() +{ + BPath path; + status_t result = find_directory(B_COMMON_SETTINGS_DIRECTORY, &path); + if (result != B_OK) + return result; + result = path.Append("nfs4_idmapper.conf"); + if (result != B_OK) + return result; + + BFile file(path.Path(), B_READ_ONLY); + if (file.InitCheck() != B_OK) + return file.InitCheck(); + + off_t size; + result = file.GetSize(&size); + if (result != B_OK) + return result; + + void* buffer = malloc(size); + if (buffer == NULL) + return B_NO_MEMORY; + + file.Read(buffer, size); + + gDomainName = reinterpret_cast(buffer); + + return B_OK; +} + + +int +main(int argc, char** argv) +{ + gRequestPort = find_port(kRequestPortName); + if (gRequestPort == B_NAME_NOT_FOUND) { + fprintf(stderr, "%s\n", strerror(gRequestPort)); + return gRequestPort; + } + + gReplyPort = find_port(kReplyPortName); + if (gReplyPort == B_NAME_NOT_FOUND) { + fprintf(stderr, "%s\n", strerror(gReplyPort)); + return gReplyPort; + } + + ReadSettings(); + + struct passwd* userInfo = getpwnam(kNobodyName); + if (userInfo != NULL) + gNobodyId = userInfo->pw_uid; + else + gNobodyId = 0; + + struct group* groupInfo = getgrnam(kNogroupName); + if (groupInfo != NULL) + gNogroupId = groupInfo->gr_gid; + else + gNogroupId = 0; + + return MainLoop(); +} + diff --git a/src/add-ons/kernel/file_systems/nfs4/idmapper/IdMapper.h b/src/add-ons/kernel/file_systems/nfs4/idmapper/IdMapper.h new file mode 100644 index 0000000000..bf0707ea1e --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/idmapper/IdMapper.h @@ -0,0 +1,26 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ +#ifndef IDMAPPER_H +#define IDMAPPER_H + + +enum MsgCode { + MsgError, + MsgReply, + MsgNameToUID, + MsgUIDToName, + MsgNameToGID, + MsgGIDToName +}; + +static const char* kRequestPortName = "nfs4idmap_request"; +static const char* kReplyPortName = "nfs4idmap_reply"; + + +#endif // IDMAPPER_H + diff --git a/src/add-ons/kernel/file_systems/nfs4/idmapper/Jamfile b/src/add-ons/kernel/file_systems/nfs4/idmapper/Jamfile new file mode 100644 index 0000000000..f9f4bb2f20 --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/idmapper/Jamfile @@ -0,0 +1,13 @@ +SubDir HAIKU_TOP src add-ons kernel file_systems nfs4 idmapper ; + +Application nfs4_idmapper_server + : + IdMapper.cpp + + : + be + $(TARGET_LIBSUPC++) + + : + nfs4_idmapper_server.rdef +; diff --git a/src/add-ons/kernel/file_systems/nfs4/idmapper/nfs4_idmapper_server.rdef b/src/add-ons/kernel/file_systems/nfs4/idmapper/nfs4_idmapper_server.rdef new file mode 100644 index 0000000000..9b601815d2 --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/idmapper/nfs4_idmapper_server.rdef @@ -0,0 +1,20 @@ +/* + * nfs4_idmapper_server.rdef + */ + +resource app_signature "application/x-vnd.Haiku-nfs4_idmapper-server"; + +resource app_flags B_EXCLUSIVE_LAUNCH | B_BACKGROUND_APP; + +resource app_version { + major = 1, + middle = 0, + minor = 0, + + variety = B_APPV_ALPHA, + internal = 0, + + short_info = "nfs4_idmapper_server", + long_info = "nfs4_idmapper_server ©2012 Haiku, Inc" +}; + 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 e2b40f9c3d..1f3c2166d1 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -15,6 +15,7 @@ #include "Connection.h" #include "Filesystem.h" +#include "IdMap.h" #include "Inode.h" #include "NFS4Defs.h" #include "RequestBuilder.h" @@ -546,6 +547,13 @@ nfs4_init() gRPCServerManager = new(std::nothrow) RPC::ServerManager; if (gRPCServerManager == NULL) return B_NO_MEMORY; + + gIdMapper = new(std::nothrow) IdMap; + if (gIdMapper == NULL) { + delete gRPCServerManager; + return B_NO_MEMORY; + } + return B_OK; } @@ -555,6 +563,7 @@ nfs4_uninit() { dprintf("NFS4 Uninit\n"); + delete gIdMapper; delete gRPCServerManager; return B_OK; From ed097dd0a27587d885a777401a519bf03991d62e Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Tue, 3 Jul 2012 21:57:08 +0200 Subject: [PATCH 118/252] nfs4: Do not attempt to set owner, owner_group when not supported --- .../kernel/file_systems/nfs4/Inode.cpp | 20 +++++++++++-------- .../kernel/file_systems/nfs4/InodeDir.cpp | 20 +++++++++++-------- .../kernel/file_systems/nfs4/InodeRegular.cpp | 20 +++++++++++-------- 3 files changed, 36 insertions(+), 24 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index 836962bdac..3a8a995cad 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -353,15 +353,19 @@ Inode::CreateLink(const char* name, const char* path, int mode) cattr[i].fData.fValue32 = mode; i++; - cattr[i].fAttribute = FATTR4_OWNER; - cattr[i].fFreePointer = true; - cattr[i].fData.fPointer = gIdMapper->GetOwner(getuid()); - i++; + if (fFilesystem->IsAttrSupported(FATTR4_OWNER)) { + cattr[i].fAttribute = FATTR4_OWNER; + cattr[i].fFreePointer = true; + cattr[i].fData.fPointer = gIdMapper->GetOwner(getuid()); + i++; + } - cattr[i].fAttribute = FATTR4_OWNER_GROUP; - cattr[i].fFreePointer = true; - cattr[i].fData.fPointer = gIdMapper->GetOwnerGroup(getgid()); - i++; + if (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(NF4LNK, name, cattr, i, path); diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp b/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp index d41ddca6f3..bde7506f66 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp @@ -34,15 +34,19 @@ Inode::CreateDir(const char* name, int mode) cattr[i].fData.fValue32 = mode; i++; - cattr[i].fAttribute = FATTR4_OWNER; - cattr[i].fFreePointer = true; - cattr[i].fData.fPointer = gIdMapper->GetOwner(getuid()); - i++; + if (fFilesystem->IsAttrSupported(FATTR4_OWNER)) { + cattr[i].fAttribute = FATTR4_OWNER; + cattr[i].fFreePointer = true; + cattr[i].fData.fPointer = gIdMapper->GetOwner(getuid()); + i++; + } - cattr[i].fAttribute = FATTR4_OWNER_GROUP; - cattr[i].fFreePointer = true; - cattr[i].fData.fPointer = gIdMapper->GetOwnerGroup(getgid()); - i++; + if (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); diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp index b0e92cbbf1..3f104fcbcf 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp @@ -91,15 +91,19 @@ Inode::Create(const char* name, int mode, int perms, OpenFileCookie* cookie, cattr[i].fData.fValue32 = perms; i++; - cattr[i].fAttribute = FATTR4_OWNER; - cattr[i].fFreePointer = true; - cattr[i].fData.fPointer = gIdMapper->GetOwner(getuid()); - i++; + if (fFilesystem->IsAttrSupported(FATTR4_OWNER)) { + cattr[i].fAttribute = FATTR4_OWNER; + cattr[i].fFreePointer = true; + cattr[i].fData.fPointer = gIdMapper->GetOwner(getuid()); + i++; + } - cattr[i].fAttribute = FATTR4_OWNER_GROUP; - cattr[i].fFreePointer = true; - cattr[i].fData.fPointer = gIdMapper->GetOwnerGroup(getgid()); - i++; + if (fFilesystem->IsAttrSupported(FATTR4_OWNER_GROUP)) { + cattr[i].fAttribute = FATTR4_OWNER_GROUP; + 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, From 6197fa881fea5641fd7c1433c3c1adf27c5d3fdf Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Tue, 3 Jul 2012 22:00:55 +0200 Subject: [PATCH 119/252] nfs4: Allow WriteStat() to set UID and GID --- src/add-ons/kernel/file_systems/nfs4/Inode.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index 3a8a995cad..3286dc6bca 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -595,7 +595,7 @@ Inode::WriteStat(const struct stat* st, uint32 mask) { status_t result; OpenFileCookie* cookie = NULL; - AttrValue attr[4]; + AttrValue attr[6]; uint32 i = 0; if ((mask & B_STAT_SIZE) != 0) { @@ -623,6 +623,20 @@ Inode::WriteStat(const struct stat* st, uint32 mask) i++; } + if ((mask & B_STAT_UID) != 0) { + attr[i].fAttribute = FATTR4_OWNER; + attr[i].fFreePointer = true; + attr[i].fData.fPointer = gIdMapper->GetOwner(st->st_uid); + i++; + } + + if ((mask & B_STAT_GID) != 0) { + attr[i].fAttribute = FATTR4_OWNER_GROUP; + attr[i].fFreePointer = true; + attr[i].fData.fPointer = gIdMapper->GetOwnerGroup(st->st_gid); + i++; + } + if ((mask & B_STAT_ACCESS_TIME) != 0) { attr[i].fAttribute = FATTR4_TIME_ACCESS_SET; attr[i].fFreePointer = true; From 16ff38f8289b93fe84a8e04aeddf33f9e78434fb Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Tue, 3 Jul 2012 22:08:35 +0200 Subject: [PATCH 120/252] nfs4: Support legacy owner and owner_group values --- src/add-ons/kernel/file_systems/nfs4/Inode.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index 3286dc6bca..5199cb2055 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -9,6 +9,7 @@ #include "Inode.h" +#include #include #include @@ -547,14 +548,20 @@ Inode::Stat(struct stat* st) if (count >= next && values[next].fAttribute == FATTR4_OWNER) { char* owner = reinterpret_cast(values[next].fData.fPointer); - st->st_uid = gIdMapper->GetUserId(owner); + if (owner != NULL && isdigit(owner[0])) + st->st_uid = atoi(owner); + else + st->st_uid = gIdMapper->GetUserId(owner); next++; } else st->st_uid = 0; if (count >= next && values[next].fAttribute == FATTR4_OWNER_GROUP) { char* group = reinterpret_cast(values[next].fData.fPointer); - st->st_gid = gIdMapper->GetGroupId(group); + if (group != NULL && isdigit(group[0])) + st->st_gid = atoi(group); + else + st->st_gid = gIdMapper->GetGroupId(group); next++; } else st->st_gid = 0; From 8f57d30ea4934abc215ae850fa3612474087d7a3 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Tue, 3 Jul 2012 22:16:08 +0200 Subject: [PATCH 121/252] nfs4: Abandon owner and owner_group when id mapping causes problems --- src/add-ons/kernel/file_systems/nfs4/Inode.cpp | 10 ++++++++-- src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp | 10 ++++++++-- src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp | 9 +++++++-- 3 files changed, 23 insertions(+), 6 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index 5199cb2055..055b6b2a68 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -340,6 +340,8 @@ Inode::Rename(Inode* from, Inode* to, const char* fromName, const char* toName) status_t Inode::CreateLink(const char* name, const char* path, int mode) { + bool badOwner = false; + do { RPC::Server* serv = fFilesystem->Server(); Request request(serv); @@ -354,14 +356,14 @@ Inode::CreateLink(const char* name, const char* path, int mode) cattr[i].fData.fValue32 = mode; i++; - if (fFilesystem->IsAttrSupported(FATTR4_OWNER)) { + if (!badOwner && fFilesystem->IsAttrSupported(FATTR4_OWNER)) { cattr[i].fAttribute = FATTR4_OWNER; cattr[i].fFreePointer = true; cattr[i].fData.fPointer = gIdMapper->GetOwner(getuid()); i++; } - if (fFilesystem->IsAttrSupported(FATTR4_OWNER_GROUP)) { + if (!badOwner && fFilesystem->IsAttrSupported(FATTR4_OWNER_GROUP)) { cattr[i].fAttribute = FATTR4_OWNER_GROUP; cattr[i].fFreePointer = true; cattr[i].fData.fPointer = gIdMapper->GetOwnerGroup(getgid()); @@ -376,6 +378,10 @@ Inode::CreateLink(const char* name, const char* path, int mode) ReplyInterpreter& reply = request.Reply(); + if (reply.NFS4Error() == NFS4ERR_BADOWNER) { + badOwner = true; + continue; + } if (_HandleErrors(reply.NFS4Error(), serv)) continue; diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp b/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp index bde7506f66..19b274351d 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp @@ -20,6 +20,8 @@ status_t Inode::CreateDir(const char* name, int mode) { + bool badOwner = false; + do { RPC::Server* serv = fFilesystem->Server(); Request request(serv); @@ -34,14 +36,14 @@ Inode::CreateDir(const char* name, int mode) cattr[i].fData.fValue32 = mode; i++; - if (fFilesystem->IsAttrSupported(FATTR4_OWNER)) { + if (!badOwner && fFilesystem->IsAttrSupported(FATTR4_OWNER)) { cattr[i].fAttribute = FATTR4_OWNER; cattr[i].fFreePointer = true; cattr[i].fData.fPointer = gIdMapper->GetOwner(getuid()); i++; } - if (fFilesystem->IsAttrSupported(FATTR4_OWNER_GROUP)) { + if (!badOwner && fFilesystem->IsAttrSupported(FATTR4_OWNER_GROUP)) { cattr[i].fAttribute = FATTR4_OWNER_GROUP; cattr[i].fFreePointer = true; cattr[i].fData.fPointer = gIdMapper->GetOwnerGroup(getgid()); @@ -56,6 +58,10 @@ Inode::CreateDir(const char* name, int mode) ReplyInterpreter& reply = request.Reply(); + if (reply.NFS4Error() == NFS4ERR_BADOWNER) { + badOwner = true; + continue; + } if (_HandleErrors(reply.NFS4Error(), serv)) continue; diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp index 3f104fcbcf..742ba45bbe 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp @@ -66,6 +66,7 @@ Inode::Create(const char* name, int mode, int perms, OpenFileCookie* cookie, cookie->fSequence = 0; cookie->fLocks = NULL; + bool badOwner = false; Filehandle fh; do { cookie->fClientId = fFilesystem->NFSServer()->ClientId(); @@ -91,14 +92,14 @@ Inode::Create(const char* name, int mode, int perms, OpenFileCookie* cookie, cattr[i].fData.fValue32 = perms; i++; - if (fFilesystem->IsAttrSupported(FATTR4_OWNER)) { + if (!badOwner && fFilesystem->IsAttrSupported(FATTR4_OWNER)) { cattr[i].fAttribute = FATTR4_OWNER; cattr[i].fFreePointer = true; cattr[i].fData.fPointer = gIdMapper->GetOwner(getuid()); i++; } - if (fFilesystem->IsAttrSupported(FATTR4_OWNER_GROUP)) { + if (!badOwner && fFilesystem->IsAttrSupported(FATTR4_OWNER_GROUP)) { cattr[i].fAttribute = FATTR4_OWNER_GROUP; cattr[i].fFreePointer = true; cattr[i].fData.fPointer = gIdMapper->GetOwnerGroup(getgid()); @@ -122,6 +123,10 @@ Inode::Create(const char* name, int mode, int perms, OpenFileCookie* cookie, ReplyInterpreter& reply = request.Reply(); + if (reply.NFS4Error() == NFS4ERR_BADOWNER) { + badOwner = true; + continue; + } if (_HandleErrors(reply.NFS4Error(), serv)) continue; From 085c6e2d99dede3cc2e2b9631040201e2a8d78d7 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Wed, 4 Jul 2012 15:45:08 +0200 Subject: [PATCH 122/252] nfs4: Fix double free at unmounting --- src/add-ons/kernel/file_systems/nfs4/Inode.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index 055b6b2a68..a57253651b 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -96,7 +96,6 @@ Inode::CreateInode(Filesystem* fs, const FileInfo &fi, Inode** _inode) Inode::~Inode() { - free(const_cast(fInfo.fName)); } From 7ef9380fb3f606dd61b82905ab1247765546817c Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Wed, 4 Jul 2012 16:23:04 +0200 Subject: [PATCH 123/252] nfs4: Fix several problems with IdMapper error handling --- .../kernel/file_systems/nfs4/IdMap.cpp | 9 ++-- .../file_systems/nfs4/idmapper/IdMapper.cpp | 44 ++++++++++++------- 2 files changed, 34 insertions(+), 19 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/IdMap.cpp b/src/add-ons/kernel/file_systems/nfs4/IdMap.cpp index 37d755947b..9a02f8b3cf 100644 --- a/src/add-ons/kernel/file_systems/nfs4/IdMap.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/IdMap.cpp @@ -89,8 +89,8 @@ IdMap::_GetValue(const char* buffer, int32 code) if (code != MsgReply) return 0; - else - return value; + + return value; } while (true); } @@ -135,8 +135,9 @@ IdMap::_GetBuffer(T value, int32 code) if (code != MsgReply) { free(buffer); return NULL; - } else - return buffer; + } + + return buffer; } while (true); } diff --git a/src/add-ons/kernel/file_systems/nfs4/idmapper/IdMapper.cpp b/src/add-ons/kernel/file_systems/nfs4/idmapper/IdMapper.cpp index a0d6c490c8..5c8d2a9905 100644 --- a/src/add-ons/kernel/file_systems/nfs4/idmapper/IdMapper.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/idmapper/IdMapper.cpp @@ -62,6 +62,8 @@ AddDomain(const char* name) { uint32 fullLength = strlen(name) + strlen(gDomainName) + 2; char* fullName = reinterpret_cast(malloc(fullLength)); + if (fullName == NULL) + return NULL; strcpy(fullName, name); strcat(fullName, "@"); @@ -93,17 +95,23 @@ UIDToName(void* buffer) { uid_t userId = *reinterpret_cast(buffer); - const char* fullName = kNobodyName; + const char* name = NULL; struct passwd* userInfo = getpwuid(userId); if (userInfo != NULL) { - const char* name = userInfo->pw_name; - fullName = AddDomain(name); + name = userInfo->pw_name; + name = AddDomain(name); } - status_t result = write_port(gReplyPort, MsgReply, fullName, - strlen(fullName) + 1); - free(const_cast(fullName)); + status_t result; + + if (name != NULL) { + result = write_port(gReplyPort, MsgReply, name, strlen(name) + 1); + free(const_cast(name)); + } else { + result = write_port(gReplyPort, MsgReply, kNobodyName, + strlen(kNobodyName) + 1); + } return result; } @@ -133,17 +141,23 @@ GIDToName(void* buffer) { gid_t groupId = *reinterpret_cast(buffer); - const char* fullName = kNogroupName; + const char* name = NULL; struct group* groupInfo = getgrgid(groupId); if (groupInfo != NULL) { - const char* name = groupInfo->gr_name; - fullName = AddDomain(name); + name = groupInfo->gr_name; + name = AddDomain(name); } - status_t result = write_port(gReplyPort, MsgReply, fullName, - strlen(fullName) + 1); - free(const_cast(fullName)); + status_t result; + + if (name != NULL) { + result = write_port(gReplyPort, MsgReply, name, strlen(name) + 1); + free(const_cast(name)); + } else { + result = write_port(gReplyPort, MsgReply, kNogroupName, + strlen(kNogroupName) + 1); + } return result; } @@ -193,7 +207,7 @@ MainLoop() result = ParseRequest(code, buffer); free(buffer); - if (result == B_BAD_PORT_ID) + if (result != B_OK) return 0; } while (true); @@ -236,13 +250,13 @@ int main(int argc, char** argv) { gRequestPort = find_port(kRequestPortName); - if (gRequestPort == B_NAME_NOT_FOUND) { + if (gRequestPort < B_OK) { fprintf(stderr, "%s\n", strerror(gRequestPort)); return gRequestPort; } gReplyPort = find_port(kReplyPortName); - if (gReplyPort == B_NAME_NOT_FOUND) { + if (gReplyPort < B_OK) { fprintf(stderr, "%s\n", strerror(gReplyPort)); return gReplyPort; } From ea70f0aa5c59adccf140ab6bd278ae23d9eff5c6 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Wed, 4 Jul 2012 16:30:21 +0200 Subject: [PATCH 124/252] nfs4: Fix error handling problems in FileInfo::UpdateFileHandles() --- .../kernel/file_systems/nfs4/FileInfo.cpp | 27 +++++++++++++------ 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/FileInfo.cpp b/src/add-ons/kernel/file_systems/nfs4/FileInfo.cpp index 1ec4daa316..4838fa4e6f 100644 --- a/src/add-ons/kernel/file_systems/nfs4/FileInfo.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/FileInfo.cpp @@ -14,13 +14,17 @@ static status_t -sParsePath(RequestBuilder& req, uint32* count, const char* _path) +ParsePath(RequestBuilder& req, uint32& count, const char* _path) { char* path = strdup(_path); + if (path == NULL) + return B_NO_MEMORY; + char* pathStart = path; char* pathEnd; + while (pathStart != NULL) { - pathEnd = strpbrk(pathStart, "/"); + pathEnd = strchr(pathStart, '/'); if (pathEnd != NULL) *pathEnd = '\0'; @@ -31,7 +35,7 @@ sParsePath(RequestBuilder& req, uint32* count, const char* _path) else pathStart = NULL; - (*count)++; + count++; } free(path); @@ -48,9 +52,15 @@ FileInfo::UpdateFileHandles(Filesystem* fs) req.PutRootFH(); uint32 lookupCount = 0; + status_t result; - sParsePath(req, &lookupCount, fs->Path()); - sParsePath(req, &lookupCount, fPath); + result = ParsePath(req, lookupCount, fs->Path()); + if (result != B_OK) + return result; + + result = ParsePath(req, lookupCount, fPath); + if (result != B_OK) + return result; if (fs->IsAttrSupported(FATTR4_FILEID)) { AttrValue attr; @@ -64,7 +74,7 @@ FileInfo::UpdateFileHandles(Filesystem* fs) req.LookUpUp(); req.GetFH(); - status_t result = request.Send(); + result = request.Send(); if (result != B_OK) return result; @@ -84,7 +94,8 @@ FileInfo::UpdateFileHandles(Filesystem* fs) if (reply.LookUpUp() == B_ENTRY_NOT_FOUND) { fParent = fHandle; return B_OK; - } else - return reply.GetFH(&fParent); + } + + return reply.GetFH(&fParent); } From dd86fd8f4c72d0247d65b7916d13e95a63e53429 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Wed, 4 Jul 2012 16:52:26 +0200 Subject: [PATCH 125/252] nfs4: Add few lacking error checks after strdup() or malloc() --- .../kernel/file_systems/nfs4/Filesystem.cpp | 18 +++++++++++++++++- src/add-ons/kernel/file_systems/nfs4/Inode.cpp | 5 +++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp b/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp index d9a69eb080..61b3ce705e 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp @@ -176,6 +176,11 @@ Filesystem::Mount(Filesystem** pfs, RPC::Server* serv, const char* fsPath, delete[] values; + if (fi.fName == NULL || fi.fPath == NULL) { + delete fs; + return B_NO_MEMORY; + } + Inode* inode; result = Inode::CreateInode(fs, fi, &inode); if (result != B_OK) { @@ -257,6 +262,15 @@ Filesystem::Migrate(const RPC::Server* serv) free(const_cast(fPath)); fPath = strdup(locs->fLocations[j].fRootPath); + + if (fPath == NULL) { + gRPCServerManager->Release(fServer); + fServer = server; + put_module(DNS_RESOLVER_MODULE_NAME); + delete[] values; + return B_NO_MEMORY; + } + break; } } @@ -265,8 +279,10 @@ Filesystem::Migrate(const RPC::Server* serv) put_module(DNS_RESOLVER_MODULE_NAME); delete[] values; - if (server == fServer) + if (server == fServer) { + gRPCServerManager->Release(server); return B_ERROR; + } NFS4Server* old = reinterpret_cast(server->PrivateData()); old->RemoveFilesystem(this); diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index a57253651b..8831e81b44 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -175,9 +175,14 @@ Inode::LookUp(const char* name, ino_t* id) fi.fHandle = fh; fi.fParent = fInfo.fHandle; fi.fName = strdup(name); + if (fi.fName == NULL) + return B_NO_MEMORY; char* path = reinterpret_cast(malloc(strlen(name) + 2 + strlen(fInfo.fPath))); + if (path == NULL) + return B_NO_MEMORY; + strcpy(path, fInfo.fPath); strcat(path, "/"); strcat(path, name); From 209c46eec428500700843ffbbc508e7bb77695bf Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Wed, 4 Jul 2012 16:56:40 +0200 Subject: [PATCH 126/252] nfs4: Let FileSystem::Mount() use FileInfo::ParsePath() --- .../kernel/file_systems/nfs4/FileInfo.cpp | 6 ++-- .../kernel/file_systems/nfs4/FileInfo.h | 4 +++ .../kernel/file_systems/nfs4/Filesystem.cpp | 28 +++---------------- 3 files changed, 12 insertions(+), 26 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/FileInfo.cpp b/src/add-ons/kernel/file_systems/nfs4/FileInfo.cpp index 4838fa4e6f..43bb3b4604 100644 --- a/src/add-ons/kernel/file_systems/nfs4/FileInfo.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/FileInfo.cpp @@ -13,8 +13,10 @@ #include "Request.h" -static status_t -ParsePath(RequestBuilder& req, uint32& count, const char* _path) +// TODO: This function probably needs more strict checking against incorrect +// paths. Correct handling of '..' and '.' also may be useful. +status_t +FileInfo::ParsePath(RequestBuilder& req, uint32& count, const char* _path) { char* path = strdup(_path); if (path == NULL) diff --git a/src/add-ons/kernel/file_systems/nfs4/FileInfo.h b/src/add-ons/kernel/file_systems/nfs4/FileInfo.h index a250262afe..169967a872 100644 --- a/src/add-ons/kernel/file_systems/nfs4/FileInfo.h +++ b/src/add-ons/kernel/file_systems/nfs4/FileInfo.h @@ -28,6 +28,7 @@ struct Filehandle { class Filesystem; +class RequestBuilder; // Complete information needed to identify a file in any situation. // Unfortunately just a filehandle is not enough even when they are persistent @@ -46,6 +47,9 @@ struct FileInfo { inline FileInfo& operator=(const FileInfo& fi); status_t UpdateFileHandles(Filesystem* fs); + + static status_t ParsePath(RequestBuilder& req, uint32& count, + const char* _path); }; struct FilesystemId { diff --git a/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp b/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp index 61b3ce705e..df8b169896 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp @@ -73,30 +73,10 @@ Filesystem::Mount(Filesystem** pfs, RPC::Server* serv, const char* fsPath, req.PutRootFH(); - // Better way of doing this will be needed uint32 lookupCount = 0; - char* path = strdup(fsPath); - char* pathStart = path; - char* pathEnd; - while (pathStart != NULL && pathStart[0] != '\0') { - pathEnd = strpbrk(pathStart, "/"); - if (pathEnd != NULL) - *pathEnd = '\0'; - if (pathEnd == pathStart) { - pathStart++; - continue; - } - - req.LookUp(pathStart); - - if (pathEnd != NULL && pathEnd[1] != '\0') - pathStart = pathEnd + 1; - else - pathStart = NULL; - - lookupCount++; - } - free(path); + status_t result = FileInfo::ParsePath(req, lookupCount, fsPath); + if (result != B_OK) + return result; req.GetFH(); req.Access(); @@ -105,7 +85,7 @@ Filesystem::Mount(Filesystem** pfs, RPC::Server* serv, const char* fsPath, FATTR4_FSID, FATTR4_FS_LOCATIONS }; req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); - status_t result = request.Send(); + result = request.Send(); if (result != B_OK) return result; From b664395b9e9243f5d2de962913803bad6e3e4751 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Wed, 4 Jul 2012 17:09:22 +0200 Subject: [PATCH 127/252] nfs4: Remove several superfluous 'else' --- .../kernel/file_systems/nfs4/IdMap.cpp | 15 +++------ .../kernel/file_systems/nfs4/Inode.cpp | 31 ++++++++----------- .../kernel/file_systems/nfs4/InodeRegular.cpp | 8 ++--- 3 files changed, 22 insertions(+), 32 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/IdMap.cpp b/src/add-ons/kernel/file_systems/nfs4/IdMap.cpp index 9a02f8b3cf..36920c010a 100644 --- a/src/add-ons/kernel/file_systems/nfs4/IdMap.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/IdMap.cpp @@ -73,8 +73,7 @@ IdMap::_GetValue(const char* buffer, int32 code) if (result != B_OK) { if (_Repair() != B_OK) return 0; - else - continue; + continue; } int32 code; @@ -83,8 +82,7 @@ IdMap::_GetValue(const char* buffer, int32 code) if (result < B_OK) { if (_Repair() != B_OK) return 0; - else - continue; + continue; } if (code != MsgReply) @@ -105,16 +103,14 @@ IdMap::_GetBuffer(T value, int32 code) if (result != B_OK) { if (_Repair() != B_OK) return NULL; - else - continue; + continue; } ssize_t size = port_buffer_size(fReplyPort); if (size < B_OK) { if (_Repair() != B_OK) return NULL; - else - continue; + continue; } int32 code; @@ -128,8 +124,7 @@ IdMap::_GetBuffer(T value, int32 code) if (_Repair() != B_OK) return 0; - else - continue; + continue; } if (code != MsgReply) { diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index 8831e81b44..e6ef4f7d78 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -718,14 +718,12 @@ Inode::_CheckLockType(short ltype, uint32 mode) case F_RDLCK: if ((mode & O_RDONLY) == 0 && (mode & O_RDWR) == 0) return EBADF; - else - return B_OK; + return B_OK; case F_WRLCK: if ((mode & O_WRONLY) == 0 && (mode & O_RDWR) == 0) return EBADF; - else - return B_OK; + return B_OK; default: return B_BAD_VALUE; @@ -981,14 +979,13 @@ Inode::_HandleErrors(uint32 nfs4Error, RPC::Server* serv, } 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) - return true; - else { + if (result != B_TIMED_OUT) { release_sem(cookie->fSnoozeCancel); return false; } - } else - return false; + return true; + } + return false; // server is in grace period, we need to wait case NFS4ERR_GRACE: @@ -1000,14 +997,13 @@ Inode::_HandleErrors(uint32 nfs4Error, RPC::Server* serv, } 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) - return true; - else { + if (result != B_TIMED_OUT) { release_sem(cookie->fSnoozeCancel); return false; } - } else - return false; + return true; + } + return false; // server has rebooted, reclaim share and try again case NFS4ERR_STALE_CLIENTID: @@ -1019,8 +1015,7 @@ Inode::_HandleErrors(uint32 nfs4Error, RPC::Server* serv, case NFS4ERR_FHEXPIRED: if (fInfo.UpdateFileHandles(fFilesystem) == B_OK) return true; - else - return false; + return false; // filesystem has been moved case NFS4ERR_LEASE_MOVED: @@ -1033,8 +1028,8 @@ Inode::_HandleErrors(uint32 nfs4Error, RPC::Server* serv, if (cookie != NULL) { fFilesystem->NFSServer()->ClientId(cookie->fClientId, true); return true; - } else - return false; + } + return false; default: return false; diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp index 742ba45bbe..2b37035867 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp @@ -175,8 +175,8 @@ Inode::Create(const char* name, int mode, int perms, OpenFileCookie* cookie, if (confirm) return _ConfirmOpen(fh, cookie); - else - return B_OK; + + return B_OK; } @@ -271,8 +271,8 @@ Inode::Open(int mode, OpenFileCookie* cookie) if (confirm) return _ConfirmOpen(fInfo.fHandle, cookie); - else - return B_OK; + + return B_OK; } From 2353db439e3844c757adca4c7e6a2b2d4c050ccb Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Wed, 4 Jul 2012 20:52:36 +0200 Subject: [PATCH 128/252] nfs4: Fix error checking after read_port() --- src/add-ons/kernel/file_systems/nfs4/IdMap.cpp | 4 ++-- src/add-ons/kernel/file_systems/nfs4/idmapper/IdMapper.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/IdMap.cpp b/src/add-ons/kernel/file_systems/nfs4/IdMap.cpp index 36920c010a..b53cbe9787 100644 --- a/src/add-ons/kernel/file_systems/nfs4/IdMap.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/IdMap.cpp @@ -118,8 +118,8 @@ IdMap::_GetBuffer(T value, int32 code) if (buffer == NULL) return NULL; - result = read_port(fReplyPort, &code, buffer, size); - if (result < B_OK) { + size = read_port(fReplyPort, &code, buffer, size); + if (size < B_OK) { free(buffer); if (_Repair() != B_OK) diff --git a/src/add-ons/kernel/file_systems/nfs4/idmapper/IdMapper.cpp b/src/add-ons/kernel/file_systems/nfs4/idmapper/IdMapper.cpp index 5c8d2a9905..2622663a9f 100644 --- a/src/add-ons/kernel/file_systems/nfs4/idmapper/IdMapper.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/idmapper/IdMapper.cpp @@ -198,13 +198,13 @@ MainLoop() return B_NO_MEMORY; int32 code; - status_t result = read_port(gRequestPort, &code, buffer, size); + size = read_port(gRequestPort, &code, buffer, size); if (size < B_OK) { free(buffer); return 0; } - result = ParseRequest(code, buffer); + status_t result = ParseRequest(code, buffer); free(buffer); if (result != B_OK) From 9054c96c17401b5ef4259cbba615ca8b8856473c Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Thu, 5 Jul 2012 01:25:17 +0200 Subject: [PATCH 129/252] Move parsing getattrinfo() result out of dns_resolver module --- headers/private/net/dns_resolver.h | 33 +++- .../kernel/file_systems/nfs4/Connection.cpp | 38 +++++ .../kernel/file_systems/nfs4/Connection.h | 3 + .../kernel/file_systems/nfs4/Filesystem.cpp | 33 ++-- .../file_systems/nfs4/kernel_interface.cpp | 30 +--- .../kernel/network/dns_resolver/Definitions.h | 6 +- .../kernel_add_on/dns_resolver.cpp | 120 +++++++++++--- .../network/dns_resolver/server/main.cpp | 150 ++++++++++++------ 8 files changed, 293 insertions(+), 120 deletions(-) diff --git a/headers/private/net/dns_resolver.h b/headers/private/net/dns_resolver.h index 179e9c2fe2..0a5cf14525 100644 --- a/headers/private/net/dns_resolver.h +++ b/headers/private/net/dns_resolver.h @@ -9,6 +9,9 @@ #define DNS_RESOLVER_H +#include +#include + #include @@ -16,10 +19,36 @@ struct dns_resolver_module { - module_info module; - status_t (*dns_resolve)(const char* host, uint32* addr); + module_info module; + status_t (*getaddrinfo)(const char* node, const char* service, + const struct addrinfo* hints, struct addrinfo** res); }; +static inline int +getaddrinfo(const char* node, const char* service, const struct addrinfo* hints, + struct addrinfo** res) +{ + dns_resolver_module* dns; + status_t result = get_module(DNS_RESOLVER_MODULE_NAME, + reinterpret_cast(&dns)); + if (result != B_OK) + return result; + + result = dns->getaddrinfo(node, service, hints, res); + + put_module(DNS_RESOLVER_MODULE_NAME); + + return result; +} + + +static inline void +freeaddrinfo(struct addrinfo* res) +{ + free(res); +} + + #endif // DNS_RESOLVER_H diff --git a/src/add-ons/kernel/file_systems/nfs4/Connection.cpp b/src/add-ons/kernel/file_systems/nfs4/Connection.cpp index 9cd6480940..6a94ba7788 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Connection.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Connection.cpp @@ -9,12 +9,14 @@ #include "Connection.h" +#include #include #include #include #include #include +#include #define LAST_FRAGMENT 0x80000000 @@ -48,6 +50,42 @@ ServerAddress::operator=(const ServerAddress& x) } +status_t +ServerAddress::ResolveName(const char* name, ServerAddress* addr) +{ + addr->fPort = 2049; + addr->fProtocol = ProtocolUDP; + + struct in_addr iaddr; + if (inet_aton(name, &iaddr) != 0) { + addr->fAddress = ntohl(iaddr.s_addr); + return B_OK; + } + + addrinfo* ai; + status_t result = getaddrinfo(name, NULL, NULL, &ai); + if (result != B_OK) + return result; + + addrinfo* current = ai; + while (current != NULL) { + if (current->ai_family == AF_INET) { + sockaddr_in* sin = reinterpret_cast(current->ai_addr); + + addr->fAddress = ntohl(sin->sin_addr.s_addr); + + freeaddrinfo(ai); + return B_OK; + } + + current = current->ai_next; + } + + freeaddrinfo(ai); + return B_NAME_NOT_FOUND; +} + + Connection::Connection(const sockaddr_in& addr, Transport proto) : fSock(-1), diff --git a/src/add-ons/kernel/file_systems/nfs4/Connection.h b/src/add-ons/kernel/file_systems/nfs4/Connection.h index dcbb2c90e0..51d0323db2 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Connection.h +++ b/src/add-ons/kernel/file_systems/nfs4/Connection.h @@ -29,6 +29,9 @@ struct ServerAddress { bool operator<(const ServerAddress& x); ServerAddress& operator=(const ServerAddress& x); + + static status_t ResolveName(const char* name, + ServerAddress* addr); }; class Connection { diff --git a/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp b/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp index df8b169896..b12871857f 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp @@ -9,11 +9,9 @@ #include "Filesystem.h" -#include #include #include -#include #include "Request.h" #include "RootInode.h" @@ -216,37 +214,25 @@ Filesystem::Migrate(const RPC::Server* serv) FSLocations* locs = reinterpret_cast(values[0].fData.fLocations); - dns_resolver_module* dns; - result = get_module(DNS_RESOLVER_MODULE_NAME, - reinterpret_cast(&dns)); - if (result != B_OK) { - delete[] values; - return result; - } - RPC::Server* server = fServer; for (uint32 i = 0; i < locs->fCount; i++) { for (uint32 j = 0; j < locs->fLocations[i].fCount; j++) { - uint32 ip; - struct in_addr addr; - if (inet_aton(locs->fLocations[i].fLocations[j], &addr) == 0) { - result = dns->dns_resolve(locs->fLocations[i].fLocations[j], - &ip); - if (result != B_OK) - continue; - } else - ip = addr.s_addr; + ServerAddress addr; - if (gRPCServerManager->Acquire(&fServer, ip, 2049, - ProtocolUDP, CreateNFS4Server) == B_OK) { + if (ServerAddress::ResolveName(locs->fLocations[i].fLocations[j], + &addr) != B_OK) + continue; + + if (gRPCServerManager->Acquire(&fServer, addr.fAddress, addr.fPort, + addr.fProtocol, CreateNFS4Server) == B_OK) { free(const_cast(fPath)); - fPath = strdup(locs->fLocations[j].fRootPath); + fPath = strdup(locs->fLocations[i].fRootPath); if (fPath == NULL) { gRPCServerManager->Release(fServer); fServer = server; - put_module(DNS_RESOLVER_MODULE_NAME); + delete[] values; return B_NO_MEMORY; } @@ -256,7 +242,6 @@ Filesystem::Migrate(const RPC::Server* serv) } } - put_module(DNS_RESOLVER_MODULE_NAME); delete[] values; if (server == fServer) { 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 1f3c2166d1..2edac96304 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -7,10 +7,8 @@ */ -#include #include -#include #include #include "Connection.h" @@ -42,7 +40,7 @@ CreateNFS4Server(RPC::Server* serv) static status_t -sParseArguments(const char* _args, uint32* _ip, char* _path) +ParseArguments(const char* _args, uint32* _ip, char* _path) { if (_args == NULL) return B_BAD_VALUE; @@ -55,26 +53,12 @@ sParseArguments(const char* _args, uint32* _ip, char* _path) } *path++ = '\0'; - status_t result; - struct in_addr addr; - if (inet_aton(args, &addr) == 0) { - dns_resolver_module* dns; - result = get_module(DNS_RESOLVER_MODULE_NAME, - reinterpret_cast(&dns)); - if (result != B_OK) { - free(args); - return result; - } + ServerAddress addr; + status_t result = ServerAddress::ResolveName(args, &addr); + if (result != B_OK) + return result; - result = dns->dns_resolve(args, _ip); - put_module(DNS_RESOLVER_MODULE_NAME); - if (result != B_OK) { - free(args); - return result; - } - } else - *_ip = addr.s_addr; - *_ip = ntohl(*_ip); + *_ip = addr.fAddress; _path[255] = '\0'; strncpy(_path, path, 255); @@ -92,7 +76,7 @@ nfs4_mount(fs_volume* volume, const char* device, uint32 flags, uint32 ip; char path[256]; - result = sParseArguments(args, &ip, path); + result = ParseArguments(args, &ip, path); if (result != B_OK) return result; diff --git a/src/add-ons/kernel/network/dns_resolver/Definitions.h b/src/add-ons/kernel/network/dns_resolver/Definitions.h index 407b2a436c..6aef5c09f8 100644 --- a/src/add-ons/kernel/network/dns_resolver/Definitions.h +++ b/src/add-ons/kernel/network/dns_resolver/Definitions.h @@ -13,9 +13,9 @@ const char* kPortNameReq = "dns_resolver_req"; const char* kPortNameRpl = "dns_resolver_rpl"; enum MsgCodes { - MsgResolveRequest = 1, - MsgResolveReply = 2, - MsgResolveError = 3 + MsgReply, + MsgError, + MsgGetAddrInfo, }; diff --git a/src/add-ons/kernel/network/dns_resolver/kernel_add_on/dns_resolver.cpp b/src/add-ons/kernel/network/dns_resolver/kernel_add_on/dns_resolver.cpp index 121c08c6c7..40d2db47b3 100644 --- a/src/add-ons/kernel/network/dns_resolver/kernel_add_on/dns_resolver.cpp +++ b/src/add-ons/kernel/network/dns_resolver/kernel_add_on/dns_resolver.cpp @@ -9,10 +9,12 @@ #include +#include #include #include #include #include +#include #include "Definitions.h" @@ -91,40 +93,120 @@ dns_resolver_uninit() } -static status_t -dns_resolve(const char* host, uint32* addr) +static void +RelocateEntries(struct addrinfo *addr) { - mutex_lock(&gPortLock); + char* generalOffset = reinterpret_cast(addr); + + struct addrinfo* current = addr; + while (current != NULL) { + uint64 addrOffset = reinterpret_cast(current->ai_addr); + uint64 nameOffset = reinterpret_cast(current->ai_canonname); + uint64 nextOffset = reinterpret_cast(current->ai_next); + + if (current->ai_addr != NULL) { + current->ai_addr = + reinterpret_cast(generalOffset + addrOffset); + } + + if (current->ai_canonname != NULL) + current->ai_canonname = generalOffset + nameOffset; + + if (current->ai_next != NULL) { + current->ai_next = + reinterpret_cast(generalOffset + nextOffset); + } + + current = current->ai_next; + } +} + + +static status_t +GetAddrInfo(const char* node, const char* service, + const struct addrinfo* hints, struct addrinfo** res) +{ + dprintf("SENDING GETADDRINFO %s\n", node); + + uint32 nodeSize = node != NULL ? strlen(node) + 1 : 1; + uint32 serviceSize = service != NULL ? strlen(service) + 1 : 1; + uint32 size = nodeSize + serviceSize + sizeof(*hints); + char* buffer = reinterpret_cast(malloc(size)); + if (buffer == NULL) + return B_NO_MEMORY; + MemoryDeleter _(buffer); + + off_t off = 0; + if (node != NULL) + strcpy(buffer + off, node); + else + buffer[off] = '\0'; + off += nodeSize; + + if (service != NULL) + strcpy(buffer + off, service); + else + buffer[off] = '\0'; + off += serviceSize; + + if (hints != NULL) + memcpy(buffer + off, hints, sizeof(*hints)); + else { + struct addrinfo *nullHints = + reinterpret_cast(buffer + off); + memset(nullHints, 0, sizeof(*nullHints)); + nullHints->ai_family = AF_UNSPEC; + } + dprintf("SENDING BUFFER %s %d\n", buffer, (int)size); + MutexLocker locker(gPortLock); do { - status_t result = write_port(gPortRequest, MsgResolveRequest, host, - strlen(host) + 1); + status_t result = write_port(gPortRequest, MsgGetAddrInfo, buffer, + size); if (result != B_OK) { result = dns_resolver_repair(); - if (result != B_OK) { - mutex_unlock(&gPortLock); + if (result != B_OK) return result; - } - continue; } + ssize_t replySize = port_buffer_size(gPortReply); + if (replySize < B_OK) { + result = dns_resolver_repair(); + if (result != B_OK) + return result; + continue; + } + + void* reply = malloc(replySize); + if (reply == NULL) + return B_NO_MEMORY; + int32 code; - result = read_port(gPortReply, &code, addr, sizeof(*addr)); - if (result < B_OK) { + replySize = read_port(gPortReply, &code, reply, replySize); + if (replySize < B_OK) { result = dns_resolver_repair(); if (result != B_OK) { - mutex_unlock(&gPortLock); + free(reply); return result; } - continue; } - mutex_unlock(&gPortLock); - if (code == MsgResolveReply) - return B_OK; - else - return *addr; + struct addrinfo *addr; + switch (code) { + case MsgReply: + addr = reinterpret_cast(reply); + RelocateEntries(addr); + *res = addr; + return B_OK; + case MsgError: + result = *reinterpret_cast(reply); + free(reply); + return result; + default: + free(reply); + return B_BAD_VALUE; + } } while (true); } @@ -150,7 +232,7 @@ static dns_resolver_module sDNSResolverModule = { dns_resolver_std_ops, }, - dns_resolve, + GetAddrInfo, }; module_info* modules[] = { diff --git a/src/add-ons/kernel/network/dns_resolver/server/main.cpp b/src/add-ons/kernel/network/dns_resolver/server/main.cpp index 3b4a14ef19..0c816ca391 100644 --- a/src/add-ons/kernel/network/dns_resolver/server/main.cpp +++ b/src/add-ons/kernel/network/dns_resolver/server/main.cpp @@ -8,81 +8,133 @@ #include +#include #include #include -#include +#include +#include #include #include "Definitions.h" +port_id gRequestPort; +port_id gReplyPort; + + status_t -resolve_dns(const char* host, uint32* addr) +GetAddrInfo(const char* buffer) { - addrinfo* ai; - addrinfo* current; - status_t result = getaddrinfo(host, NULL, NULL, &ai); + const char* node = buffer[0] == '\0' ? NULL : buffer; + uint32 nodeSize = node != NULL ? strlen(node) + 1 : 1; + + const char* service = buffer[nodeSize] == '\0' ? NULL : buffer + nodeSize; + uint32 serviceSize = service != NULL ? strlen(service) + 1 : 1; + + const struct addrinfo* hints = + reinterpret_cast(buffer + nodeSize + serviceSize); + + struct addrinfo* ai; + status_t result = getaddrinfo(node, service, hints, &ai); if (result != B_OK) - return result; + return write_port(gReplyPort, MsgError, &result, sizeof(result)); - current = ai; + uint32 addrsSize = ai == NULL ? 0 : sizeof(addrinfo); + uint32 namesSize = 0; + uint32 socksSize = 0; + addrinfo* current = ai; while (current != NULL) { - if (current->ai_family == AF_INET) { - sockaddr_in* sin = reinterpret_cast(current->ai_addr); - *addr = sin->sin_addr.s_addr; - freeaddrinfo(ai); - return B_OK; + if (current->ai_canonname != NULL) + namesSize += strlen(current->ai_canonname) + 1; + if (current->ai_addr != NULL) { + if (current->ai_family == AF_INET) + socksSize += sizeof(sockaddr_in); + else + socksSize += sizeof(sockaddr_in6); } - + if (current->ai_next != NULL) + addrsSize += sizeof(addrinfo); current = current->ai_next; } - freeaddrinfo(ai); - return B_NAME_NOT_FOUND; + uint32 totalSize = addrsSize + namesSize + socksSize; + char* reply = reinterpret_cast(malloc(totalSize)); + if (reply == NULL) { + free(reply); + + result = B_NO_MEMORY; + return write_port(gReplyPort, MsgError, &result, sizeof(result)); + } + + uint32 addrPos = 0; + uint32 namePos = addrsSize; + uint32 sockPos = addrsSize + namesSize; + + current = ai; + while (current != NULL) { + if (current->ai_canonname != NULL) { + strcpy(reply + namePos, current->ai_canonname); + uint32 nSize = strlen(current->ai_canonname) + 1; + current->ai_canonname = reinterpret_cast(namePos); + namePos += nSize; + } + if (current->ai_addr != NULL) { + if (current->ai_family == AF_INET) { + memcpy(reply + sockPos, current->ai_addr, sizeof(sockaddr_in)); + current->ai_addr = reinterpret_cast(sockPos); + sockPos += sizeof(sockaddr_in); + } else { + memcpy(reply + sockPos, current->ai_addr, sizeof(sockaddr_in6)); + current->ai_addr = reinterpret_cast(sockPos); + sockPos += sizeof(sockaddr_in6); + } + } + + addrinfo* next = current->ai_next; + current->ai_next = reinterpret_cast(addrPos) + 1; + memcpy(reply + addrPos, current, sizeof(addrinfo)); + addrPos += sizeof(addrinfo); + + current = next; + } + + return write_port(gReplyPort, MsgReply, reply, totalSize); } status_t -main_loop(port_id portReq, port_id portRpl) +MainLoop() { do { - ssize_t size = port_buffer_size(portReq); + ssize_t size = port_buffer_size(gRequestPort); if (size < B_OK) return 0; void* buffer = malloc(size); if (buffer == NULL) return B_NO_MEMORY; + MemoryDeleter _(buffer); int32 code; - status_t result = read_port(portReq, &code, buffer, size); - if (size < B_OK) { - free(buffer); - return 0; - } - - if (code != MsgResolveRequest) { - free(buffer); - continue; - } - - uint32 addr; - result = resolve_dns(reinterpret_cast(buffer), &addr); - free(buffer); - - if (result == B_OK) - result = write_port(portRpl, MsgResolveReply, &addr, sizeof(addr)); - else { - result = write_port(portRpl, MsgResolveError, &result, - sizeof(result)); - } - - if (result == B_BAD_PORT_ID) + size = read_port(gRequestPort, &code, buffer, size); + if (size < B_OK) return 0; + status_t result; + switch (code) { + case MsgGetAddrInfo: + result = GetAddrInfo(reinterpret_cast(buffer)); + default: + result = B_BAD_VALUE; + write_port(gReplyPort, MsgError, &result, sizeof(result)); + result = B_OK; + } + + if (result != B_OK) + return 0; } while (true); } @@ -90,18 +142,18 @@ main_loop(port_id portReq, port_id portRpl) int main(int argc, char** argv) { - port_id portReq = find_port(kPortNameReq); - if (portReq == B_NAME_NOT_FOUND) { - fprintf(stderr, "%s\n", strerror(portReq)); - return portReq; + gRequestPort = find_port(kPortNameReq); + if (gRequestPort < B_OK) { + fprintf(stderr, "%s\n", strerror(gRequestPort)); + return gRequestPort; } - port_id portRpl = find_port(kPortNameRpl); - if (portRpl == B_NAME_NOT_FOUND) { - fprintf(stderr, "%s\n", strerror(portRpl)); - return portRpl; + gReplyPort = find_port(kPortNameRpl); + if (gReplyPort < B_OK) { + fprintf(stderr, "%s\n", strerror(gReplyPort)); + return gReplyPort; } - return main_loop(portReq, portRpl); + return MainLoop(); } From 92284dcc2cc283de8cf553889891ae46aa2ba991 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Sun, 8 Jul 2012 23:33:44 +0200 Subject: [PATCH 130/252] nfs4: Use semaphore to cancel threads instead of interrupt_thread() --- headers/os/drivers/KernelExport.h | 1 - .../kernel/file_systems/nfs4/Connection.cpp | 44 +++++++++++++++++++ .../kernel/file_systems/nfs4/Connection.h | 1 + .../kernel/file_systems/nfs4/NFS4Server.cpp | 12 +++-- .../kernel/file_systems/nfs4/NFS4Server.h | 1 + .../kernel/file_systems/nfs4/RPCServer.cpp | 6 +-- src/system/kernel/thread.cpp | 14 ------ 7 files changed, 57 insertions(+), 22 deletions(-) diff --git a/headers/os/drivers/KernelExport.h b/headers/os/drivers/KernelExport.h index 14c707dc66..3e2e5848dd 100644 --- a/headers/os/drivers/KernelExport.h +++ b/headers/os/drivers/KernelExport.h @@ -138,7 +138,6 @@ extern bool cancel_timer(timer *t); /* kernel threads */ extern thread_id spawn_kernel_thread(thread_func function, const char *name, int32 priority, void *arg); -extern status_t interrupt_thread(thread_id id); /* signal functions */ extern int send_signal_etc(pid_t thread, uint signal, uint32 flags); diff --git a/src/add-ons/kernel/file_systems/nfs4/Connection.cpp b/src/add-ons/kernel/file_systems/nfs4/Connection.cpp index 6a94ba7788..f7381c747f 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Connection.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Connection.cpp @@ -88,6 +88,7 @@ ServerAddress::ResolveName(const char* name, ServerAddress* addr) Connection::Connection(const sockaddr_in& addr, Transport proto) : + fWaitCancel(create_sem(0, NULL)), fSock(-1), fProtocol(proto), fServerAddress(addr) @@ -115,6 +116,7 @@ Connection::~Connection() if (fSock != -1) close(fSock); mutex_destroy(&fSockLock); + delete_sem(fWaitCancel); } @@ -192,7 +194,25 @@ ConnectionStream::Receive(void** pbuffer, uint32* psize) int32 record_size; bool last_one; + + object_wait_info object[2]; + object[0].object = fWaitCancel; + object[0].type = B_OBJECT_TYPE_SEMAPHORE; + object[0].events = B_EVENT_ACQUIRE_SEMAPHORE; + + object[1].object = fSock; + object[1].type = B_OBJECT_TYPE_FD; + object[1].events = B_EVENT_READ; + do { + result = wait_for_objects(object, 2); + if (result < B_OK || + (object[0].events & B_EVENT_ACQUIRE_SEMAPHORE) != 0) { + free(buffer); + return ECONNABORTED; + } else if ((object[1].events & B_EVENT_READ) == 0) + continue; + // There is only one listener thread per connection. No need to lock. uint32 received = 0; do { @@ -253,6 +273,26 @@ ConnectionPacket::Receive(void** pbuffer, uint32* psize) if (buffer == NULL) return B_NO_MEMORY; + object_wait_info object[2]; + object[0].object = fWaitCancel; + object[0].type = B_OBJECT_TYPE_SEMAPHORE; + object[0].events = B_EVENT_ACQUIRE_SEMAPHORE; + + object[1].object = fSock; + object[1].type = B_OBJECT_TYPE_FD; + object[1].events = B_EVENT_READ; + + do { + result = wait_for_objects(object, 2); + if (result < B_OK || + (object[0].events & B_EVENT_ACQUIRE_SEMAPHORE) != 0) { + free(buffer); + return ECONNABORTED; + } else if ((object[1].events & B_EVENT_READ) == 0) + continue; + break; + } while (true); + // There is only one listener thread per connection. No need to lock. size = recv(fSock, buffer, size, 0); if (size < 0) { @@ -333,7 +373,9 @@ Connection::_Connect() status_t Connection::Reconnect() { + release_sem(fWaitCancel); close(fSock); + acquire_sem(fWaitCancel); return _Connect(); } @@ -341,6 +383,8 @@ Connection::Reconnect() void Connection::Disconnect() { + release_sem(fWaitCancel); + int sock = fSock; fSock = -1; close(sock); diff --git a/src/add-ons/kernel/file_systems/nfs4/Connection.h b/src/add-ons/kernel/file_systems/nfs4/Connection.h index 51d0323db2..eff2a6673f 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Connection.h +++ b/src/add-ons/kernel/file_systems/nfs4/Connection.h @@ -53,6 +53,7 @@ protected: Transport proto); status_t _Connect(); + sem_id fWaitCancel; int fSock; mutex fSockLock; diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp index 49886ef592..70757d34df 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp @@ -16,6 +16,7 @@ NFS4Server::NFS4Server(RPC::Server* serv) : fThreadCancel(true), + fWaitCancel(create_sem(1, NULL)), fLeaseTime(0), fClientIdLastUse(0), fUseCount(0), @@ -31,10 +32,11 @@ NFS4Server::~NFS4Server() { fThreadCancel = true; fUseCount = 0; - interrupt_thread(fThread); + release_sem(fWaitCancel); status_t result; wait_for_thread(fThread, &result); + delete_sem(fWaitCancel); mutex_destroy(&fClientIdLock); mutex_destroy(&fFSLock); } @@ -302,8 +304,12 @@ NFS4Server::_Renewal() { while (!fThreadCancel) { // TODO: operations like OPEN, READ, CLOSE, etc also renew leases - snooze_etc(sSecToBigTime(fLeaseTime - 2), B_SYSTEM_TIMEBASE, - B_RELATIVE_TIMEOUT | B_CAN_INTERRUPT); + status_t result = acquire_sem_etc(fWaitCancel, 1, + B_RELATIVE_TIMEOUT, sSecToBigTime(fLeaseTime - 2)); + if (result != B_TIMED_OUT) { + release_sem(fWaitCancel); + return B_OK; + } uint64 clientId = fClientId; diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h index 2979923bb4..fdf61e88b8 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h @@ -45,6 +45,7 @@ private: static status_t _RenewalThreadStart(void* ptr); thread_id fThread; bool fThreadCancel; + sem_id fWaitCancel; uint32 fLeaseTime; diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp b/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp index 3230caa172..5e017149ad 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp @@ -89,12 +89,11 @@ Server::~Server() fThreadCancel = true; fConnection->Disconnect(); - interrupt_thread(fThread); - - delete fConnection; status_t result; wait_for_thread(fThread, &result); + + delete fConnection; } @@ -205,7 +204,6 @@ status_t Server::Repair() { fThreadCancel = true; - interrupt_thread(fThread); status_t result = fConnection->Reconnect(); if (result != B_OK) diff --git a/src/system/kernel/thread.cpp b/src/system/kernel/thread.cpp index 022b8a1173..6c95268c44 100644 --- a/src/system/kernel/thread.cpp +++ b/src/system/kernel/thread.cpp @@ -3007,20 +3007,6 @@ kill_thread(thread_id id) } -status_t -interrupt_thread(thread_id id) -{ - Thread* thread = Thread::GetAndLock(id); - if (thread == NULL) - return B_BAD_THREAD_ID; - BReference threadReference(thread, true); - ThreadLocker threadLocker(thread, true); - - InterruptsSpinLocker schedulerLocker(gSchedulerLock); - return thread_interrupt(thread, false); -} - - status_t send_data(thread_id thread, int32 code, const void *buffer, size_t bufferSize) { From fcb41396a11ae546a4f1d1123468fe2c6a0f1891 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Sun, 8 Jul 2012 23:35:05 +0200 Subject: [PATCH 131/252] dns_resolver: Remove accidentally added debug messages --- .../network/dns_resolver/kernel_add_on/dns_resolver.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/add-ons/kernel/network/dns_resolver/kernel_add_on/dns_resolver.cpp b/src/add-ons/kernel/network/dns_resolver/kernel_add_on/dns_resolver.cpp index 40d2db47b3..eb58f5a143 100644 --- a/src/add-ons/kernel/network/dns_resolver/kernel_add_on/dns_resolver.cpp +++ b/src/add-ons/kernel/network/dns_resolver/kernel_add_on/dns_resolver.cpp @@ -126,8 +126,6 @@ static status_t GetAddrInfo(const char* node, const char* service, const struct addrinfo* hints, struct addrinfo** res) { - dprintf("SENDING GETADDRINFO %s\n", node); - uint32 nodeSize = node != NULL ? strlen(node) + 1 : 1; uint32 serviceSize = service != NULL ? strlen(service) + 1 : 1; uint32 size = nodeSize + serviceSize + sizeof(*hints); @@ -157,7 +155,7 @@ GetAddrInfo(const char* node, const char* service, memset(nullHints, 0, sizeof(*nullHints)); nullHints->ai_family = AF_UNSPEC; } - dprintf("SENDING BUFFER %s %d\n", buffer, (int)size); + MutexLocker locker(gPortLock); do { status_t result = write_port(gPortRequest, MsgGetAddrInfo, buffer, From 00a8558cc75d9aee84f6d9b34c28d6706952558c Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Sun, 8 Jul 2012 23:56:45 +0200 Subject: [PATCH 132/252] nfs4: Rename Filehandle to FileHandle and Filesystem to FileSystem --- .../kernel/file_systems/nfs4/Cookie.cpp | 4 +- src/add-ons/kernel/file_systems/nfs4/Cookie.h | 4 +- .../kernel/file_systems/nfs4/FileInfo.cpp | 4 +- .../kernel/file_systems/nfs4/FileInfo.h | 44 +++++----- .../nfs4/{Filesystem.cpp => FileSystem.cpp} | 36 ++++---- .../nfs4/{Filesystem.h => FileSystem.h} | 40 ++++----- .../kernel/file_systems/nfs4/Inode.cpp | 86 +++++++++---------- src/add-ons/kernel/file_systems/nfs4/Inode.h | 16 ++-- .../kernel/file_systems/nfs4/InodeDir.cpp | 30 +++---- .../kernel/file_systems/nfs4/InodeRegular.cpp | 54 ++++++------ src/add-ons/kernel/file_systems/nfs4/Jamfile | 2 +- .../kernel/file_systems/nfs4/NFS4Server.cpp | 28 +++--- .../kernel/file_systems/nfs4/NFS4Server.h | 10 +-- .../file_systems/nfs4/ReplyInterpreter.cpp | 6 +- .../file_systems/nfs4/ReplyInterpreter.h | 2 +- .../file_systems/nfs4/RequestBuilder.cpp | 8 +- .../kernel/file_systems/nfs4/RequestBuilder.h | 2 +- .../kernel/file_systems/nfs4/RootInode.cpp | 6 +- .../file_systems/nfs4/kernel_interface.cpp | 20 ++--- 19 files changed, 201 insertions(+), 201 deletions(-) rename src/add-ons/kernel/file_systems/nfs4/{Filesystem.cpp => FileSystem.cpp} (88%) rename src/add-ons/kernel/file_systems/nfs4/{Filesystem.h => FileSystem.h} (76%) diff --git a/src/add-ons/kernel/file_systems/nfs4/Cookie.cpp b/src/add-ons/kernel/file_systems/nfs4/Cookie.cpp index 6c39b970a9..0102d68b86 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Cookie.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Cookie.cpp @@ -124,7 +124,7 @@ Cookie::CancelAll() MutexLocker _(fRequestLock); RequestEntry* ent = fRequests; while (ent != NULL) { - fFilesystem->Server()->WakeCall(ent->fRequest); + fFileSystem->Server()->WakeCall(ent->fRequest); ent = ent->fNext; } @@ -219,7 +219,7 @@ OpenFileCookie::DeleteLock(LockInfo* lock) status_t OpenFileCookie::_ReleaseLockOwner(LockOwner* owner) { - Request request(fFilesystem->Server()); + Request request(fFileSystem->Server()); RequestBuilder& req = request.Builder(); req.ReleaseLockOwner(this, owner); diff --git a/src/add-ons/kernel/file_systems/nfs4/Cookie.h b/src/add-ons/kernel/file_systems/nfs4/Cookie.h index cda0791738..364dc17c5d 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Cookie.h +++ b/src/add-ons/kernel/file_systems/nfs4/Cookie.h @@ -11,7 +11,7 @@ #include -#include "Filesystem.h" +#include "FileSystem.h" struct LockOwner { @@ -55,7 +55,7 @@ struct Cookie { RequestEntry* fNext; }; - Filesystem* fFilesystem; + FileSystem* fFileSystem; RequestEntry* fRequests; mutex fRequestLock; diff --git a/src/add-ons/kernel/file_systems/nfs4/FileInfo.cpp b/src/add-ons/kernel/file_systems/nfs4/FileInfo.cpp index 43bb3b4604..22a86ecfbc 100644 --- a/src/add-ons/kernel/file_systems/nfs4/FileInfo.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/FileInfo.cpp @@ -9,7 +9,7 @@ #include "FileInfo.h" -#include "Filesystem.h" +#include "FileSystem.h" #include "Request.h" @@ -46,7 +46,7 @@ FileInfo::ParsePath(RequestBuilder& req, uint32& count, const char* _path) status_t -FileInfo::UpdateFileHandles(Filesystem* fs) +FileInfo::UpdateFileHandles(FileSystem* fs) { Request request(fs->Server()); RequestBuilder& req = request.Builder(); diff --git a/src/add-ons/kernel/file_systems/nfs4/FileInfo.h b/src/add-ons/kernel/file_systems/nfs4/FileInfo.h index 169967a872..28b541218b 100644 --- a/src/add-ons/kernel/file_systems/nfs4/FileInfo.h +++ b/src/add-ons/kernel/file_systems/nfs4/FileInfo.h @@ -17,27 +17,27 @@ #define NFS4_FHSIZE 128 -struct Filehandle { +struct FileHandle { uint8 fSize; - uint8 fFH[NFS4_FHSIZE]; + uint8 fData[NFS4_FHSIZE]; - inline Filehandle(); - inline Filehandle(const Filehandle& fh); - inline Filehandle& operator=(const Filehandle& fh); + inline FileHandle(); + inline FileHandle(const FileHandle& fh); + inline FileHandle& operator=(const FileHandle& fh); }; -class Filesystem; +class FileSystem; class RequestBuilder; // Complete information needed to identify a file in any situation. -// Unfortunately just a filehandle is not enough even when they are persistent -// since OPEN requires both parent filehandle and file name (just like LOOKUP). +// Unfortunately just a FileHandle is not enough even when they are persistent +// since OPEN requires both parent FileHandle and file name (just like LOOKUP). struct FileInfo { uint64 fFileId; - Filehandle fHandle; + FileHandle fHandle; - Filehandle fParent; + FileHandle fParent; const char* fName; const char* fPath; @@ -46,23 +46,23 @@ struct FileInfo { inline FileInfo(const FileInfo& fi); inline FileInfo& operator=(const FileInfo& fi); - status_t UpdateFileHandles(Filesystem* fs); + status_t UpdateFileHandles(FileSystem* fs); static status_t ParsePath(RequestBuilder& req, uint32& count, const char* _path); }; -struct FilesystemId { +struct FileSystemId { uint64 fMajor; uint64 fMinor; - inline bool operator==(const FilesystemId& fsid) const; - inline bool operator!=(const FilesystemId& fsid) const; + inline bool operator==(const FileSystemId& fsid) const; + inline bool operator!=(const FileSystemId& fsid) const; }; inline -Filehandle::Filehandle() +FileHandle::FileHandle() : fSize(0) { @@ -70,19 +70,19 @@ Filehandle::Filehandle() inline -Filehandle::Filehandle(const Filehandle& fh) +FileHandle::FileHandle(const FileHandle& fh) : fSize(fh.fSize) { - memcpy(fFH, fh.fFH, fSize); + memcpy(fData, fh.fData, fSize); } -inline Filehandle& -Filehandle::operator=(const Filehandle& fh) +inline FileHandle& +FileHandle::operator=(const FileHandle& fh) { fSize = fh.fSize; - memcpy(fFH, fh.fFH, fSize); + memcpy(fData, fh.fData, fSize); return *this; } @@ -135,14 +135,14 @@ FileInfo::operator=(const FileInfo& fi) inline bool -FilesystemId::operator==(const FilesystemId& fsid) const +FileSystemId::operator==(const FileSystemId& fsid) const { return fMajor == fsid.fMajor && fMinor == fsid.fMinor; } inline bool -FilesystemId::operator!=(const FilesystemId& fsid) const +FileSystemId::operator!=(const FileSystemId& fsid) const { return !operator==(fsid); } diff --git a/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp b/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp similarity index 88% rename from src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp rename to src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp index b12871857f..a8ab9d4f67 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp @@ -7,7 +7,7 @@ */ -#include "Filesystem.h" +#include "FileSystem.h" #include @@ -21,7 +21,7 @@ extern RPC::ServerManager* gRPCServerManager; extern RPC::ProgramData* CreateNFS4Server(RPC::Server* serv); -Filesystem::Filesystem() +FileSystem::FileSystem() : fNext(NULL), fPrev(NULL), @@ -35,9 +35,9 @@ Filesystem::Filesystem() } -Filesystem::~Filesystem() +FileSystem::~FileSystem() { - NFSServer()->RemoveFilesystem(this); + NFSServer()->RemoveFileSystem(this); mutex_destroy(&fOpenLock); @@ -63,7 +63,7 @@ sGetPath(const char* root, const char* path) status_t -Filesystem::Mount(Filesystem** pfs, RPC::Server* serv, const char* fsPath, +FileSystem::Mount(FileSystem** pfs, RPC::Server* serv, const char* fsPath, dev_t id) { Request request(serv); @@ -94,7 +94,7 @@ Filesystem::Mount(Filesystem** pfs, RPC::Server* serv, const char* fsPath, for (uint32 i = 0; i < lookupCount; i++) reply.LookUp(); - Filehandle fh; + FileHandle fh; reply.GetFH(&fh); uint32 allowed; @@ -111,7 +111,7 @@ Filesystem::Mount(Filesystem** pfs, RPC::Server* serv, const char* fsPath, if (result != B_OK || count < 2) return result; - Filesystem* fs = new(std::nothrow) Filesystem; + FileSystem* fs = new(std::nothrow) FileSystem; if (fs == NULL) return B_NO_MEMORY; @@ -122,8 +122,8 @@ Filesystem::Mount(Filesystem** pfs, RPC::Server* serv, const char* fsPath, fs->fExpireType = values[1].fData.fValue32; // FATTR4_FSID is mandatory - FilesystemId* fsid = - reinterpret_cast(values[2].fData.fPointer); + FileSystemId* fsid = + reinterpret_cast(values[2].fData.fPointer); if (count == 4 && values[3].fAttribute == FATTR4_FS_LOCATIONS) { FSLocations* locs = @@ -168,7 +168,7 @@ Filesystem::Mount(Filesystem** pfs, RPC::Server* serv, const char* fsPath, fs->fRoot = reinterpret_cast(inode); - fs->NFSServer()->AddFilesystem(fs); + fs->NFSServer()->AddFileSystem(fs); *pfs = fs; return B_OK; @@ -176,7 +176,7 @@ Filesystem::Mount(Filesystem** pfs, RPC::Server* serv, const char* fsPath, status_t -Filesystem::GetInode(ino_t id, Inode** _inode) +FileSystem::GetInode(ino_t id, Inode** _inode) { FileInfo fi; status_t result = fInoIdMap.GetFileInfo(&fi, id); @@ -197,7 +197,7 @@ Filesystem::GetInode(ino_t id, Inode** _inode) status_t -Filesystem::Migrate(const RPC::Server* serv) +FileSystem::Migrate(const RPC::Server* serv) { MutexLocker _(fOpenLock); if (serv != fServer) @@ -250,8 +250,8 @@ Filesystem::Migrate(const RPC::Server* serv) } NFS4Server* old = reinterpret_cast(server->PrivateData()); - old->RemoveFilesystem(this); - NFSServer()->AddFilesystem(this); + old->RemoveFileSystem(this); + NFSServer()->AddFileSystem(this); gRPCServerManager->Release(server); @@ -260,7 +260,7 @@ Filesystem::Migrate(const RPC::Server* serv) OpenFileCookie* -Filesystem::OpenFilesLock() +FileSystem::OpenFilesLock() { mutex_lock(&fOpenLock); return fOpenFiles; @@ -268,14 +268,14 @@ Filesystem::OpenFilesLock() void -Filesystem::OpenFilesUnlock() +FileSystem::OpenFilesUnlock() { mutex_unlock(&fOpenLock); } void -Filesystem::AddOpenFile(OpenFileCookie* cookie) +FileSystem::AddOpenFile(OpenFileCookie* cookie) { MutexLocker _(fOpenLock); @@ -289,7 +289,7 @@ Filesystem::AddOpenFile(OpenFileCookie* cookie) void -Filesystem::RemoveOpenFile(OpenFileCookie* cookie) +FileSystem::RemoveOpenFile(OpenFileCookie* cookie) { MutexLocker _(fOpenLock); if (cookie == fOpenFiles) diff --git a/src/add-ons/kernel/file_systems/nfs4/Filesystem.h b/src/add-ons/kernel/file_systems/nfs4/FileSystem.h similarity index 76% rename from src/add-ons/kernel/file_systems/nfs4/Filesystem.h rename to src/add-ons/kernel/file_systems/nfs4/FileSystem.h index 9073e67169..1099f2788e 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Filesystem.h +++ b/src/add-ons/kernel/file_systems/nfs4/FileSystem.h @@ -17,11 +17,11 @@ class Inode; class RootInode; -class Filesystem { +class FileSystem { public: - static status_t Mount(Filesystem** pfs, RPC::Server* serv, + static status_t Mount(FileSystem** pfs, RPC::Server* serv, const char* path, dev_t id); - ~Filesystem(); + ~FileSystem(); status_t GetInode(ino_t id, Inode** inode); inline Inode* Root(); @@ -41,17 +41,17 @@ public: inline NFS4Server* NFSServer(); inline const char* Path() const; - inline const FilesystemId& FsId() const; + inline const FileSystemId& FsId() const; inline uint64 AllocFileId(); inline dev_t DevId() const; inline InodeIdMap* InoIdMap(); - Filesystem* fNext; - Filesystem* fPrev; + FileSystem* fNext; + FileSystem* fPrev; private: - Filesystem(); + FileSystem(); OpenFileCookie* fOpenFiles; uint32 fOpenCount; @@ -60,7 +60,7 @@ private: uint32 fExpireType; uint32 fSupAttrs[2]; - FilesystemId fFsId; + FileSystemId fFsId; const char* fPath; RootInode* fRoot; @@ -75,77 +75,77 @@ private: inline Inode* -Filesystem::Root() +FileSystem::Root() { return reinterpret_cast(fRoot); } inline uint32 -Filesystem::OpenFilesCount() +FileSystem::OpenFilesCount() { return fOpenCount; } inline bool -Filesystem::IsAttrSupported(Attribute attr) const +FileSystem::IsAttrSupported(Attribute attr) const { return sIsAttrSet(attr, fSupAttrs, 2); } inline uint32 -Filesystem::ExpireType() const +FileSystem::ExpireType() const { return fExpireType; } inline RPC::Server* -Filesystem::Server() +FileSystem::Server() { return fServer; } inline NFS4Server* -Filesystem::NFSServer() +FileSystem::NFSServer() { return reinterpret_cast(fServer->PrivateData()); } inline const char* -Filesystem::Path() const +FileSystem::Path() const { return fPath; } -inline const FilesystemId& -Filesystem::FsId() const +inline const FileSystemId& +FileSystem::FsId() const { return fFsId; } inline uint64 -Filesystem::AllocFileId() +FileSystem::AllocFileId() { return atomic_add64(&fId, 1); } inline dev_t -Filesystem::DevId() const +FileSystem::DevId() const { return fDevId; } inline InodeIdMap* -Filesystem::InoIdMap() +FileSystem::InoIdMap() { return &fInoIdMap; } diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index e6ef4f7d78..5650947543 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -25,7 +25,7 @@ Inode::Inode() status_t -Inode::CreateInode(Filesystem* fs, const FileInfo &fi, Inode** _inode) +Inode::CreateInode(FileSystem* fs, const FileInfo &fi, Inode** _inode) { Inode* inode = NULL; if (fs->Root() == NULL) @@ -37,7 +37,7 @@ Inode::CreateInode(Filesystem* fs, const FileInfo &fi, Inode** _inode) return B_NO_MEMORY; inode->fInfo = fi; - inode->fFilesystem = fs; + inode->fFileSystem = fs; do { RPC::Server* serv = fs->Server(); @@ -78,8 +78,8 @@ Inode::CreateInode(Filesystem* fs, const FileInfo &fi, Inode** _inode) inode->fType = values[0].fData.fValue32; // FATTR4_FSID is mandatory - FilesystemId* fsid = - reinterpret_cast(values[1].fData.fPointer); + FileSystemId* fsid = + reinterpret_cast(values[1].fData.fPointer); if (*fsid != fs->FsId()) { delete[] values; return B_ENTRY_NOT_FOUND; @@ -111,7 +111,7 @@ Inode::LookUp(const char* name, ino_t* id) } do { - RPC::Server* serv = fFilesystem->Server(); + RPC::Server* serv = fFileSystem->Server(); Request request(serv); RequestBuilder& req = request.Builder(); @@ -144,7 +144,7 @@ Inode::LookUp(const char* name, ino_t* id) if (result != B_OK) return result; - Filehandle fh; + FileHandle fh; reply.GetFH(&fh); AttrValue* values; @@ -154,16 +154,16 @@ Inode::LookUp(const char* name, ino_t* id) return result; // FATTR4_FSID is mandatory - FilesystemId* fsid = - reinterpret_cast(values[0].fData.fPointer); - if (*fsid != fFilesystem->FsId()) { + FileSystemId* fsid = + reinterpret_cast(values[0].fData.fPointer); + if (*fsid != fFileSystem->FsId()) { delete[] values; return B_ENTRY_NOT_FOUND; } uint64 fileId; if (count < 2 || values[1].fAttribute != FATTR4_FILEID) - fileId = fFilesystem->AllocFileId(); + fileId = fFileSystem->AllocFileId(); else fileId = values[1].fData.fValue64; delete[] values; @@ -188,7 +188,7 @@ Inode::LookUp(const char* name, ino_t* id) strcat(path, name); fi.fPath = path; - fFilesystem->InoIdMap()->AddEntry(fi, *id); + fFileSystem->InoIdMap()->AddEntry(fi, *id); return B_OK; } while (true); @@ -199,7 +199,7 @@ status_t Inode::Link(Inode* dir, const char* name) { do { - RPC::Server* serv = fFilesystem->Server(); + RPC::Server* serv = fFileSystem->Server(); Request request(serv); RequestBuilder& req = request.Builder(); @@ -214,16 +214,16 @@ Inode::Link(Inode* dir, const char* name) ReplyInterpreter& reply = request.Reply(); - // filehandle has expired + // FileHandle has expired if (reply.NFS4Error() == NFS4ERR_FHEXPIRED) { - fInfo.UpdateFileHandles(fFilesystem); - dir->fInfo.UpdateFileHandles(dir->fFilesystem); + fInfo.UpdateFileHandles(fFileSystem); + dir->fInfo.UpdateFileHandles(dir->fFileSystem); continue; } // filesystem has been moved if (reply.NFS4Error() == NFS4ERR_MOVED) { - fFilesystem->Migrate(serv); + fFileSystem->Migrate(serv); continue; } @@ -237,13 +237,13 @@ Inode::Link(Inode* dir, const char* name) // May cause problem similar to Rename (described below). When node's is has -// more than one hard link and we delete the name it stores for filehandle +// more than one hard link and we delete the name it stores for FileHandle // restoration node will inocorectly become unavailable. status_t Inode::Remove(const char* name, FileType type) { do { - RPC::Server* serv = fFilesystem->Server(); + RPC::Server* serv = fFileSystem->Server(); Request request(serv); RequestBuilder& req = request.Builder(); @@ -293,18 +293,18 @@ Inode::Remove(const char* name, FileType type) } -// Rename may cause some problems if filehandles are volatile and local Inode +// Rename may cause some problems if FileHandles are volatile and local Inode // object exists for renamed node. It's stored filename will become invalid -// and, consequnetly, filehandle restoration will fail. Probably, it will +// and, consequnetly, FileHandle restoration will fail. Probably, it will // be much easier to solve this problem if more metadata is cached. status_t Inode::Rename(Inode* from, Inode* to, const char* fromName, const char* toName) { - if (from->fFilesystem != to->fFilesystem) + if (from->fFileSystem != to->fFileSystem) return B_DONT_DO_THAT; do { - RPC::Server* serv = from->fFilesystem->Server(); + RPC::Server* serv = from->fFileSystem->Server(); Request request(serv); RequestBuilder& req = request.Builder(); @@ -319,16 +319,16 @@ Inode::Rename(Inode* from, Inode* to, const char* fromName, const char* toName) ReplyInterpreter& reply = request.Reply(); - // filehandle has expired + // FileHandle has expired if (reply.NFS4Error() == NFS4ERR_FHEXPIRED) { - from->fInfo.UpdateFileHandles(from->fFilesystem); - to->fInfo.UpdateFileHandles(to->fFilesystem); + from->fInfo.UpdateFileHandles(from->fFileSystem); + to->fInfo.UpdateFileHandles(to->fFileSystem); continue; } // filesystem has been moved if (reply.NFS4Error() == NFS4ERR_MOVED) { - from->fFilesystem->Migrate(serv); + from->fFileSystem->Migrate(serv); continue; } @@ -347,7 +347,7 @@ Inode::CreateLink(const char* name, const char* path, int mode) bool badOwner = false; do { - RPC::Server* serv = fFilesystem->Server(); + RPC::Server* serv = fFileSystem->Server(); Request request(serv); RequestBuilder& req = request.Builder(); @@ -360,14 +360,14 @@ Inode::CreateLink(const char* name, const char* path, int mode) cattr[i].fData.fValue32 = mode; i++; - if (!badOwner && fFilesystem->IsAttrSupported(FATTR4_OWNER)) { + 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)) { + if (!badOwner && fFileSystem->IsAttrSupported(FATTR4_OWNER_GROUP)) { cattr[i].fAttribute = FATTR4_OWNER_GROUP; cattr[i].fFreePointer = true; cattr[i].fData.fPointer = gIdMapper->GetOwnerGroup(getgid()); @@ -403,7 +403,7 @@ Inode::ReadLink(void* buffer, size_t* length) return B_BAD_VALUE; do { - RPC::Server* serv = fFilesystem->Server(); + RPC::Server* serv = fFileSystem->Server(); Request request(serv); RequestBuilder& req = request.Builder(); @@ -434,7 +434,7 @@ status_t Inode::Access(int mode) { do { - RPC::Server* serv = fFilesystem->Server(); + RPC::Server* serv = fFileSystem->Server(); Request request(serv); RequestBuilder& req = request.Builder(); @@ -482,7 +482,7 @@ status_t Inode::Stat(struct stat* st) { do { - RPC::Server* serv = fFilesystem->Server(); + RPC::Server* serv = fFileSystem->Server(); Request request(serv); RequestBuilder& req = request.Builder(); @@ -671,7 +671,7 @@ Inode::WriteStat(const struct stat* st, uint32 mask) } do { - RPC::Server* serv = fFilesystem->Server(); + RPC::Server* serv = fFileSystem->Server(); Request request(serv); RequestBuilder& req = request.Builder(); @@ -742,7 +742,7 @@ Inode::TestLock(OpenFileCookie* cookie, struct flock* lock) return result; do { - RPC::Server* serv = fFilesystem->Server(); + RPC::Server* serv = fFileSystem->Server(); Request request(serv); RequestBuilder& req = request.Builder(); @@ -812,7 +812,7 @@ Inode::AcquireLock(OpenFileCookie* cookie, const struct flock* lock, do { MutexLocker ownerLocker(linfo->fOwner->fLock); - RPC::Server* serv = fFilesystem->Server(); + RPC::Server* serv = fFileSystem->Server(); Request request(serv); RequestBuilder& req = request.Builder(); @@ -881,7 +881,7 @@ Inode::ReleaseLock(OpenFileCookie* cookie, const struct flock* lock) do { MutexLocker ownerLocker(linfo->fOwner->fLock); - RPC::Server* serv = fFilesystem->Server(); + RPC::Server* serv = fFileSystem->Server(); Request request(serv); RequestBuilder& req = request.Builder(); @@ -926,7 +926,7 @@ Inode::ReleaseAllLocks(OpenFileCookie* cookie) do { MutexLocker ownerLocker(linfo->fOwner->fLock); - RPC::Server* serv = fFilesystem->Server(); + RPC::Server* serv = fFileSystem->Server(); Request request(serv); RequestBuilder& req = request.Builder(); @@ -989,7 +989,7 @@ Inode::_HandleErrors(uint32 nfs4Error, RPC::Server* serv, // server is in grace period, we need to wait case NFS4ERR_GRACE: - leaseTime = fFilesystem->NFSServer()->LeaseTime(); + leaseTime = fFileSystem->NFSServer()->LeaseTime(); if (cookie == NULL) { snooze_etc(sSecToBigTime(leaseTime) / 3, B_SYSTEM_TIMEBASE, B_RELATIVE_TIMEOUT); @@ -1008,25 +1008,25 @@ Inode::_HandleErrors(uint32 nfs4Error, RPC::Server* serv, // server has rebooted, reclaim share and try again case NFS4ERR_STALE_CLIENTID: case NFS4ERR_STALE_STATEID: - fFilesystem->NFSServer()->ServerRebooted(cookie->fClientId); + fFileSystem->NFSServer()->ServerRebooted(cookie->fClientId); return true; - // filehandle has expired + // FileHandle has expired case NFS4ERR_FHEXPIRED: - if (fInfo.UpdateFileHandles(fFilesystem) == B_OK) + if (fInfo.UpdateFileHandles(fFileSystem) == B_OK) return true; return false; // filesystem has been moved case NFS4ERR_LEASE_MOVED: case NFS4ERR_MOVED: - fFilesystem->Migrate(serv); + fFileSystem->Migrate(serv); return true; // lease has expired case NFS4ERR_EXPIRED: if (cookie != NULL) { - fFilesystem->NFSServer()->ClientId(cookie->fClientId, true); + fFileSystem->NFSServer()->ClientId(cookie->fClientId, true); return true; } return false; diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h b/src/add-ons/kernel/file_systems/nfs4/Inode.h index 76445e709c..91751bb91e 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -14,21 +14,21 @@ #include #include "Cookie.h" -#include "Filesystem.h" +#include "FileSystem.h" #include "NFS4Defs.h" #include "ReplyInterpreter.h" class Inode { public: - static status_t CreateInode(Filesystem* fs, const FileInfo& fi, + static status_t CreateInode(FileSystem* fs, const FileInfo& fi, Inode** inode); ~Inode(); inline ino_t ID() const; inline mode_t Type() const; inline const char* Name() const; - inline Filesystem* FileSystem() const; + inline FileSystem* GetFileSystem() const; status_t LookUp(const char* name, ino_t* id); @@ -75,7 +75,7 @@ protected: RPC::Server* serv, OpenFileCookie* cookie = NULL); - status_t _ConfirmOpen(const Filehandle& fh, + status_t _ConfirmOpen(const FileHandle& fh, OpenFileCookie* cookie); status_t _ReadDirOnce(DirEntry** dirents, uint32* count, @@ -92,7 +92,7 @@ protected: uint32 fType; FileInfo fInfo; - Filesystem* fFilesystem; + FileSystem* fFileSystem; }; @@ -128,10 +128,10 @@ Inode::Name() const } -inline Filesystem* -Inode::FileSystem() const +inline FileSystem* +Inode::GetFileSystem() const { - return fFilesystem; + return fFileSystem; } diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp b/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp index 19b274351d..5f3c25c77b 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp @@ -23,7 +23,7 @@ Inode::CreateDir(const char* name, int mode) bool badOwner = false; do { - RPC::Server* serv = fFilesystem->Server(); + RPC::Server* serv = fFileSystem->Server(); Request request(serv); RequestBuilder& req = request.Builder(); @@ -36,14 +36,14 @@ Inode::CreateDir(const char* name, int mode) cattr[i].fData.fValue32 = mode; i++; - if (!badOwner && fFilesystem->IsAttrSupported(FATTR4_OWNER)) { + 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)) { + if (!badOwner && fFileSystem->IsAttrSupported(FATTR4_OWNER_GROUP)) { cattr[i].fAttribute = FATTR4_OWNER_GROUP; cattr[i].fFreePointer = true; cattr[i].fData.fPointer = gIdMapper->GetOwnerGroup(getgid()); @@ -79,7 +79,7 @@ Inode::OpenDir(OpenDirCookie* cookie) return B_NOT_A_DIRECTORY; do { - RPC::Server* serv = fFilesystem->Server(); + RPC::Server* serv = fFileSystem->Server(); Request request(serv); RequestBuilder& req = request.Builder(); @@ -105,7 +105,7 @@ Inode::OpenDir(OpenDirCookie* cookie) if (allowed & ACCESS4_READ != ACCESS4_READ) return B_PERMISSION_DENIED; - cookie->fFilesystem = fFilesystem; + cookie->fFileSystem = fFileSystem; cookie->fCookie = 0; cookie->fCookieVerf = 2; @@ -119,7 +119,7 @@ Inode::_ReadDirOnce(DirEntry** dirents, uint32* count, OpenDirCookie* cookie, bool* eof) { do { - RPC::Server* serv = fFilesystem->Server(); + RPC::Server* serv = fFileSystem->Server(); Request request(serv); RequestBuilder& req = request.Builder(); @@ -155,7 +155,7 @@ Inode::_FillDirEntry(struct dirent* de, ino_t id, const char* name, uint32 pos, if (pos + entSize + nameSize > size) return B_BUFFER_OVERFLOW; - de->d_dev = fFilesystem->DevId(); + de->d_dev = fFileSystem->DevId(); de->d_ino = id; de->d_reclen = entSize + nameSize; if (de->d_reclen % 8 != 0) @@ -171,7 +171,7 @@ status_t Inode::_ReadDirUp(struct dirent* de, uint32 pos, uint32 size) { do { - RPC::Server* serv = fFilesystem->Server(); + RPC::Server* serv = fFileSystem->Server(); Request request(serv); RequestBuilder& req = request.Builder(); @@ -179,7 +179,7 @@ Inode::_ReadDirUp(struct dirent* de, uint32 pos, uint32 size) req.LookUpUp(); req.GetFH(); - if (fFilesystem->IsAttrSupported(FATTR4_FILEID)) { + if (fFileSystem->IsAttrSupported(FATTR4_FILEID)) { Attribute attr[] = { FATTR4_FILEID }; req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); } @@ -198,11 +198,11 @@ Inode::_ReadDirUp(struct dirent* de, uint32 pos, uint32 size) if (result != B_OK) return result; - Filehandle fh; + FileHandle fh; reply.GetFH(&fh); uint64 fileId; - if (fFilesystem->IsAttrSupported(FATTR4_FILEID)) { + if (fFileSystem->IsAttrSupported(FATTR4_FILEID)) { AttrValue* values; uint32 count; reply.GetAttr(&values, &count); @@ -212,7 +212,7 @@ Inode::_ReadDirUp(struct dirent* de, uint32 pos, uint32 size) fileId = values[0].fData.fValue64; delete[] values; } else - fileId = fFilesystem->AllocFileId(); + fileId = fFileSystem->AllocFileId(); return _FillDirEntry(de, _FileIdToInoT(fileId), "..", pos, size); } while (true); @@ -273,15 +273,15 @@ Inode::ReadDir(void* _buffer, uint32 size, uint32* _count, // FATTR4_FSID is mandatory void* data = dirents[i].fAttrs[0].fData.fPointer; - FilesystemId* fsid = reinterpret_cast(data); - if (*fsid != fFilesystem->FsId()) + FileSystemId* fsid = reinterpret_cast(data); + if (*fsid != fFileSystem->FsId()) continue; ino_t id; if (dirents[i].fAttrCount == 2) id = _FileIdToInoT(dirents[i].fAttrs[1].fData.fValue64); else - id = _FileIdToInoT(fFilesystem->AllocFileId()); + id = _FileIdToInoT(fFileSystem->AllocFileId()); const char* name = dirents[i].fName; if (_FillDirEntry(de, id, name, pos, size) == B_BUFFER_OVERFLOW) { diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp index 2b37035867..9ecb03a239 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp @@ -18,10 +18,10 @@ status_t -Inode::_ConfirmOpen(const Filehandle& fh, OpenFileCookie* cookie) +Inode::_ConfirmOpen(const FileHandle& fh, OpenFileCookie* cookie) { do { - RPC::Server* serv = fFilesystem->Server(); + RPC::Server* serv = fFileSystem->Server(); Request request(serv); RequestBuilder& req = request.Builder(); @@ -32,7 +32,7 @@ Inode::_ConfirmOpen(const Filehandle& fh, OpenFileCookie* cookie) status_t result = request.Send(); if (result != B_OK) { - fFilesystem->RemoveOpenFile(cookie); + fFileSystem->RemoveOpenFile(cookie); return result; } @@ -44,7 +44,7 @@ Inode::_ConfirmOpen(const Filehandle& fh, OpenFileCookie* cookie) reply.PutFH(); result = reply.OpenConfirm(&cookie->fStateSeq); if (result != B_OK) { - fFilesystem->RemoveOpenFile(cookie); + fFileSystem->RemoveOpenFile(cookie); return result; } @@ -67,11 +67,11 @@ Inode::Create(const char* name, int mode, int perms, OpenFileCookie* cookie, cookie->fLocks = NULL; bool badOwner = false; - Filehandle fh; + FileHandle fh; do { - cookie->fClientId = fFilesystem->NFSServer()->ClientId(); + cookie->fClientId = fFileSystem->NFSServer()->ClientId(); - RPC::Server* serv = fFilesystem->Server(); + RPC::Server* serv = fFileSystem->Server(); Request request(serv); RequestBuilder& req = request.Builder(); @@ -92,14 +92,14 @@ Inode::Create(const char* name, int mode, int perms, OpenFileCookie* cookie, cattr[i].fData.fValue32 = perms; i++; - if (!badOwner && fFilesystem->IsAttrSupported(FATTR4_OWNER)) { + 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)) { + if (!badOwner && fFileSystem->IsAttrSupported(FATTR4_OWNER_GROUP)) { cattr[i].fAttribute = FATTR4_OWNER_GROUP; cattr[i].fFreePointer = true; cattr[i].fData.fPointer = gIdMapper->GetOwnerGroup(getgid()); @@ -112,7 +112,7 @@ Inode::Create(const char* name, int mode, int perms, OpenFileCookie* cookie, req.GetFH(); - if (fFilesystem->IsAttrSupported(FATTR4_FILEID)) { + if (fFileSystem->IsAttrSupported(FATTR4_FILEID)) { Attribute attr[] = { FATTR4_FILEID }; req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); } @@ -135,7 +135,7 @@ Inode::Create(const char* name, int mode, int perms, OpenFileCookie* cookie, reply.GetFH(&fh); uint64 fileId; - if (fFilesystem->IsAttrSupported(FATTR4_FILEID)) { + if (fFileSystem->IsAttrSupported(FATTR4_FILEID)) { AttrValue* values; uint32 count; result = reply.GetAttr(&values, &count); @@ -146,7 +146,7 @@ Inode::Create(const char* name, int mode, int perms, OpenFileCookie* cookie, delete[] values; } else - fileId = fFilesystem->AllocFileId(); + fileId = fFileSystem->AllocFileId(); *id = _FileIdToInoT(fileId); @@ -163,15 +163,15 @@ Inode::Create(const char* name, int mode, int perms, OpenFileCookie* cookie, strcat(path, name); fi.fPath = path; - fFilesystem->InoIdMap()->AddEntry(fi, *id); + fFileSystem->InoIdMap()->AddEntry(fi, *id); - cookie->fFilesystem = fFilesystem; + cookie->fFileSystem = fFileSystem; cookie->fInfo = fi; break; } while (true); - fFilesystem->AddOpenFile(cookie); + fFileSystem->AddOpenFile(cookie); if (confirm) return _ConfirmOpen(fh, cookie); @@ -186,16 +186,16 @@ Inode::Open(int mode, OpenFileCookie* cookie) bool confirm; status_t result; - cookie->fFilesystem = fFilesystem; + cookie->fFileSystem = fFileSystem; cookie->fInfo = fInfo; cookie->fMode = mode; cookie->fSequence = 0; cookie->fLocks = NULL; do { - cookie->fClientId = fFilesystem->NFSServer()->ClientId(); + cookie->fClientId = fFileSystem->NFSServer()->ClientId(); - RPC::Server* serv = fFilesystem->Server(); + RPC::Server* serv = fFileSystem->Server(); Request request(serv); RequestBuilder& req = request.Builder(); @@ -203,7 +203,7 @@ Inode::Open(int mode, OpenFileCookie* cookie) // Since we are opening the file using a pair (parentFH, name) we // need to check for race conditions. - if (fFilesystem->IsAttrSupported(FATTR4_FILEID)) { + if (fFileSystem->IsAttrSupported(FATTR4_FILEID)) { req.PutFH(fInfo.fParent); req.LookUp(fInfo.fName); AttrValue attr; @@ -211,7 +211,7 @@ Inode::Open(int mode, OpenFileCookie* cookie) attr.fFreePointer = false; attr.fData.fValue64 = fInfo.fFileId; req.Verify(&attr, 1); - } else if (fFilesystem->ExpireType() == FH4_PERSISTENT) { + } else if (fFileSystem->ExpireType() == FH4_PERSISTENT) { req.PutFH(fInfo.fParent); req.LookUp(fInfo.fName); AttrValue attr; @@ -246,8 +246,8 @@ Inode::Open(int mode, OpenFileCookie* cookie) // Verify if the file we want to open is the file this Inode // represents. - if (fFilesystem->IsAttrSupported(FATTR4_FILEID) || - fFilesystem->ExpireType() == FH4_PERSISTENT) { + if (fFileSystem->IsAttrSupported(FATTR4_FILEID) || + fFileSystem->ExpireType() == FH4_PERSISTENT) { reply.PutFH(); result = reply.LookUp(); if (result != B_OK) @@ -267,7 +267,7 @@ Inode::Open(int mode, OpenFileCookie* cookie) break; } while (true); - fFilesystem->AddOpenFile(cookie); + fFileSystem->AddOpenFile(cookie); if (confirm) return _ConfirmOpen(fInfo.fHandle, cookie); @@ -279,10 +279,10 @@ Inode::Open(int mode, OpenFileCookie* cookie) status_t Inode::Close(OpenFileCookie* cookie) { - fFilesystem->RemoveOpenFile(cookie); + fFileSystem->RemoveOpenFile(cookie); do { - RPC::Server* serv = fFilesystem->Server(); + RPC::Server* serv = fFileSystem->Server(); Request request(serv); RequestBuilder& req = request.Builder(); @@ -320,7 +320,7 @@ Inode::Read(OpenFileCookie* cookie, off_t pos, void* buffer, size_t* _length) while (size < *_length && !eof) { do { - RPC::Server* serv = fFilesystem->Server(); + RPC::Server* serv = fFileSystem->Server(); Request request(serv); RequestBuilder& req = request.Builder(); @@ -366,7 +366,7 @@ Inode::Write(OpenFileCookie* cookie, off_t pos, const void* _buffer, while (size < *_length) { do { - RPC::Server* serv = fFilesystem->Server(); + RPC::Server* serv = fFileSystem->Server(); Request request(serv); RequestBuilder& req = request.Builder(); diff --git a/src/add-ons/kernel/file_systems/nfs4/Jamfile b/src/add-ons/kernel/file_systems/nfs4/Jamfile index 822bf4147e..5350ac5a9b 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Jamfile +++ b/src/add-ons/kernel/file_systems/nfs4/Jamfile @@ -7,7 +7,7 @@ KernelAddon nfs4 : Cookie.cpp Connection.cpp FileInfo.cpp - Filesystem.cpp + FileSystem.cpp IdMap.cpp Inode.cpp InodeDir.cpp diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp index 70757d34df..2ed40353b6 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp @@ -7,7 +7,7 @@ */ -#include "Filesystem.h" +#include "FileSystem.h" #include "Inode.h" #include "NFS4Server.h" #include "Request.h" @@ -20,7 +20,7 @@ NFS4Server::NFS4Server(RPC::Server* serv) fLeaseTime(0), fClientIdLastUse(0), fUseCount(0), - fFilesystems(NULL), + fFileSystems(NULL), fServer(serv) { mutex_init(&fClientIdLock, NULL); @@ -52,7 +52,7 @@ NFS4Server::ServerRebooted(uint64 clientId) // reclaim all opened files and held locks from all filesystems MutexLocker _(fFSLock); - Filesystem* fs = fFilesystems; + FileSystem* fs = fFileSystems; while (fs != NULL) { OpenFileCookie* current = fs->OpenFilesLock(); while (current != NULL) { @@ -157,14 +157,14 @@ NFS4Server::_ReclaimLocks(OpenFileCookie* cookie) void -NFS4Server::AddFilesystem(Filesystem* fs) +NFS4Server::AddFileSystem(FileSystem* fs) { MutexLocker _(fFSLock); fs->fPrev = NULL; - fs->fNext = fFilesystems; - if (fFilesystems != NULL) - fFilesystems->fPrev = fs; - fFilesystems = fs; + fs->fNext = fFileSystems; + if (fFileSystems != NULL) + fFileSystems->fPrev = fs; + fFileSystems = fs; fUseCount += fs->OpenFilesCount(); if (fs->OpenFilesCount() > 0 && fThreadCancel) _StartRenewing(); @@ -172,11 +172,11 @@ NFS4Server::AddFilesystem(Filesystem* fs) void -NFS4Server::RemoveFilesystem(Filesystem* fs) +NFS4Server::RemoveFileSystem(FileSystem* fs) { MutexLocker _(fFSLock); - if (fs == fFilesystems) - fFilesystems = fs->fNext; + if (fs == fFileSystems) + fFileSystems = fs->fNext; if (fs->fNext) fs->fNext->fPrev = fs->fPrev; @@ -223,11 +223,11 @@ NFS4Server::ClientId(uint64 prevId, bool forceNew) status_t -NFS4Server::FilesystemMigrated() +NFS4Server::FileSystemMigrated() { // reclaim all opened files and held locks from all filesystems MutexLocker _(fFSLock); - Filesystem* fs = fFilesystems; + FileSystem* fs = fFileSystems; while (fs != NULL) { fs->Migrate(fServer); fs = fs->fNext; @@ -330,7 +330,7 @@ NFS4Server::_Renewal() ServerRebooted(clientId); break; case NFS4ERR_LEASE_MOVED: - FilesystemMigrated(); + FileSystemMigrated(); break; } } diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h index fdf61e88b8..210e3fa153 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h @@ -14,7 +14,7 @@ #include "RPCServer.h" -class Filesystem; +class FileSystem; class OpenFileCookie; class NFS4Server : public RPC::ProgramData { @@ -23,10 +23,10 @@ public: virtual ~NFS4Server(); uint64 ServerRebooted(uint64 clientId); - status_t FilesystemMigrated(); + status_t FileSystemMigrated(); - void AddFilesystem(Filesystem* fs); - void RemoveFilesystem(Filesystem* fs); + void AddFileSystem(FileSystem* fs); + void RemoveFileSystem(FileSystem* fs); inline void IncUsage(); inline void DecUsage(); @@ -55,7 +55,7 @@ private: mutex fClientIdLock; uint32 fUseCount; - Filesystem* fFilesystems; + FileSystem* fFileSystems; mutex fFSLock; RPC::Server* fServer; diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp index 43755b2687..8306a586e7 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp @@ -166,7 +166,7 @@ ReplyInterpreter::GetAttr(AttrValue** attrs, uint32* count) status_t -ReplyInterpreter::GetFH(Filehandle* fh) +ReplyInterpreter::GetFH(FileHandle* fh) { status_t res = _OperationError(OpGetFH); if (res != B_OK) @@ -179,7 +179,7 @@ ReplyInterpreter::GetFH(Filehandle* fh) if (fh != NULL) { fh->fSize = size; - memcpy(fh->fFH, ptr, size); + memcpy(fh->fData, ptr, size); } return fReply->Stream().IsEOF() ? B_BAD_VALUE : B_OK; @@ -538,7 +538,7 @@ ReplyInterpreter::_DecodeAttrs(XDR::ReadStream& str, AttrValue** attrs, values[current].fAttribute = FATTR4_FSID; values[current].fFreePointer = true; - FilesystemId fsid; + FileSystemId fsid; fsid.fMajor = stream.GetUHyper(); fsid.fMinor = stream.GetUHyper(); diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h index 8e99e9eb7b..eedd9ea645 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h @@ -71,7 +71,7 @@ public: status_t Close(); status_t Create(); status_t GetAttr(AttrValue** attrs, uint32* count); - status_t GetFH(Filehandle* fh); + status_t GetFH(FileHandle* fh); status_t Link(); status_t Lock(LockInfo* linfo); status_t LockT(uint64* pos, uint64* len, LockType* type); diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp index 81cade2607..e9007fad0f 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp @@ -402,7 +402,7 @@ RequestBuilder::OpenConfirm(uint32 seq, const uint32* id, uint32 stateSeq) status_t -RequestBuilder::PutFH(const Filehandle& fh) +RequestBuilder::PutFH(const FileHandle& fh) { if (fProcedure != ProcCompound) return B_BAD_VALUE; @@ -410,7 +410,7 @@ RequestBuilder::PutFH(const Filehandle& fh) return B_NO_MEMORY; fRequest->Stream().AddUInt(OpPutFH); - fRequest->Stream().AddOpaque(fh.fFH, fh.fSize); + fRequest->Stream().AddOpaque(fh.fData, fh.fSize); fOpCount++; return B_OK; @@ -761,8 +761,8 @@ RequestBuilder::_EncodeAttrs(XDR::WriteStream& stream, AttrValue* attr, } if (i < count && attr[i].fAttribute == FATTR4_FILEHANDLE) { - Filehandle* fh = reinterpret_cast(attr[i].fData.fPointer); - str.AddOpaque(fh->fFH, fh->fSize); + FileHandle* fh = reinterpret_cast(attr[i].fData.fPointer); + str.AddOpaque(fh->fData, fh->fSize); i++; } diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h index f59aac7940..753a8378bd 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h @@ -54,7 +54,7 @@ public: uint32 count = 0, bool excl = false); status_t OpenConfirm(uint32 seq, const uint32* id, uint32 stateSeq); - status_t PutFH(const Filehandle& fh); + status_t PutFH(const FileHandle& fh); status_t PutRootFH(); status_t Read(const uint32* id, uint32 stateSeq, uint64 pos, uint32 len); diff --git a/src/add-ons/kernel/file_systems/nfs4/RootInode.cpp b/src/add-ons/kernel/file_systems/nfs4/RootInode.cpp index 4b8ed2eb35..d5830cea7d 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RootInode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RootInode.cpp @@ -18,7 +18,7 @@ status_t RootInode::ReadInfo(struct fs_info* info) { do { - RPC::Server* serv = fFilesystem->Server(); + RPC::Server* serv = fFileSystem->Server(); Request request(serv); RequestBuilder& req = request.Builder(); @@ -97,7 +97,7 @@ bool RootInode::ProbeMigration() { do { - RPC::Server* serv = fFilesystem->Server(); + RPC::Server* serv = fFileSystem->Server(); Request request(serv); RequestBuilder& req = request.Builder(); @@ -126,7 +126,7 @@ status_t RootInode::GetLocations(AttrValue** attrv) { do { - RPC::Server* serv = fFilesystem->Server(); + RPC::Server* serv = fFileSystem->Server(); Request request(serv); RequestBuilder& req = request.Builder(); 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 2edac96304..223bb6279d 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -12,7 +12,7 @@ #include #include "Connection.h" -#include "Filesystem.h" +#include "FileSystem.h" #include "IdMap.h" #include "Inode.h" #include "NFS4Defs.h" @@ -86,8 +86,8 @@ nfs4_mount(fs_volume* volume, const char* device, uint32 flags, if (result != B_OK) return result; - Filesystem* fs; - result = Filesystem::Mount(&fs, server, path, volume->id); + FileSystem* fs; + result = FileSystem::Mount(&fs, server, path, volume->id); if (result != B_OK) { gRPCServerManager->Release(server); return result; @@ -119,7 +119,7 @@ static status_t nfs4_get_vnode(fs_volume* volume, ino_t id, fs_vnode* vnode, int* _type, uint32* _flags, bool reenter) { - Filesystem* fs = reinterpret_cast(volume->private_volume); + FileSystem* fs = reinterpret_cast(volume->private_volume); Inode* inode; status_t result = fs->GetInode(id, &inode); if (result != B_OK) @@ -138,7 +138,7 @@ nfs4_get_vnode(fs_volume* volume, ino_t id, fs_vnode* vnode, int* _type, static status_t nfs4_unmount(fs_volume* volume) { - Filesystem* fs = reinterpret_cast(volume->private_volume); + FileSystem* fs = reinterpret_cast(volume->private_volume); RPC::Server* server = fs->Server(); delete fs; @@ -151,7 +151,7 @@ nfs4_unmount(fs_volume* volume) static status_t nfs4_read_fs_info(fs_volume* volume, struct fs_info* info) { - Filesystem* fs = reinterpret_cast(volume->private_volume); + FileSystem* fs = reinterpret_cast(volume->private_volume); RootInode* inode = reinterpret_cast(fs->Root()); return inode->ReadInfo(info); } @@ -183,12 +183,12 @@ nfs4_get_vnode_name(fs_volume* volume, fs_vnode* vnode, char* buffer, static status_t nfs4_put_vnode(fs_volume* volume, fs_vnode* vnode, bool reenter) { - Filesystem* fs = reinterpret_cast(volume->private_volume); + FileSystem* fs = reinterpret_cast(volume->private_volume); Inode* inode = reinterpret_cast(vnode->private_node); if (fs->Root() == inode) return B_OK; - inode->FileSystem()->InoIdMap()->RemoveEntry(inode->ID()); + inode->GetFileSystem()->InoIdMap()->RemoveEntry(inode->ID()); delete inode; return B_OK; @@ -202,12 +202,12 @@ nfs4_remove_vnode(fs_volume* volume, fs_vnode* vnode, bool reenter) // side are only an attempt to simulate local filesystem. Hence, // this hook is the same as put_vnode(). - Filesystem* fs = reinterpret_cast(volume->private_volume); + FileSystem* fs = reinterpret_cast(volume->private_volume); Inode* inode = reinterpret_cast(vnode->private_node); if (fs->Root() == inode) return B_OK; - inode->FileSystem()->InoIdMap()->RemoveEntry(inode->ID()); + inode->GetFileSystem()->InoIdMap()->RemoveEntry(inode->ID()); delete inode; return B_OK; From 78fc85a6ba25da91d4a0a591d53e0fad073f50d9 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Tue, 10 Jul 2012 20:57:52 +0200 Subject: [PATCH 133/252] nfs4: Cache file attributes and filesystem info --- .../kernel/file_systems/nfs4/FileSystem.h | 6 +- .../kernel/file_systems/nfs4/Inode.cpp | 113 +++++++++++++----- src/add-ons/kernel/file_systems/nfs4/Inode.h | 6 + .../kernel/file_systems/nfs4/InodeDir.cpp | 2 + .../kernel/file_systems/nfs4/InodeRegular.cpp | 4 + .../kernel/file_systems/nfs4/RootInode.cpp | 53 ++++++-- .../kernel/file_systems/nfs4/RootInode.h | 24 +++- 7 files changed, 164 insertions(+), 44 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/FileSystem.h b/src/add-ons/kernel/file_systems/nfs4/FileSystem.h index 1099f2788e..3a30659329 100644 --- a/src/add-ons/kernel/file_systems/nfs4/FileSystem.h +++ b/src/add-ons/kernel/file_systems/nfs4/FileSystem.h @@ -24,7 +24,7 @@ public: ~FileSystem(); status_t GetInode(ino_t id, Inode** inode); - inline Inode* Root(); + inline RootInode* Root(); status_t Migrate(const RPC::Server* serv); @@ -74,10 +74,10 @@ private: }; -inline Inode* +inline RootInode* FileSystem::Root() { - return reinterpret_cast(fRoot); + return fRoot; } diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index 5650947543..181ef37ca6 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -20,7 +20,10 @@ Inode::Inode() + : + fAttrCacheExpire(0) { + mutex_init(&fAttrCacheLock, NULL); } @@ -96,6 +99,7 @@ Inode::CreateInode(FileSystem* fs, const FileInfo &fi, Inode** _inode) Inode::~Inode() { + mutex_destroy(&fAttrCacheLock); } @@ -288,7 +292,11 @@ Inode::Remove(const char* name, FileType type) return result; reply.PutFH(); - return reply.Remove(); + result = reply.Remove(); + + fFileSystem->Root()->MakeInfoInvalid(); + + return result; } while (true); } @@ -391,7 +399,11 @@ Inode::CreateLink(const char* name, const char* path, int mode) reply.PutFH(); - return reply.Create(); + result = reply.Create(); + + fFileSystem->Root()->MakeInfoInvalid(); + + return result; } while (true); } @@ -481,6 +493,36 @@ Inode::Access(int mode) status_t Inode::Stat(struct stat* st) { + status_t result = _UpdateAttrCache(); + if (result != B_OK) + return result; + + // Do not touch other members of struct stat + st->st_size = fAttrCache.st_size; + st->st_mode = fAttrCache.st_mode; + st->st_nlink = fAttrCache.st_nlink; + st->st_uid = fAttrCache.st_uid; + st->st_gid = fAttrCache.st_gid; + st->st_atim = fAttrCache.st_atim; + st->st_ctim = fAttrCache.st_ctim; + st->st_crtim = fAttrCache.st_crtim; + st->st_mtim = fAttrCache.st_mtim; + + return B_OK; +} + + +status_t +Inode::_UpdateAttrCache(bool force) +{ + if (!force && fAttrCacheExpire > time(NULL)) + return B_OK; + + MutexLocker _(fAttrCacheLock); + + if (fAttrCacheExpire > time(NULL)) + return B_OK; + do { RPC::Server* serv = fFileSystem->Server(); Request request(serv); @@ -516,12 +558,12 @@ Inode::Stat(struct stat* st) delete[] values; return B_BAD_VALUE; } - st->st_size = values[0].fData.fValue64; + fAttrCache.st_size = values[0].fData.fValue64; uint32 next = 1; - st->st_mode = Type(); + fAttrCache.st_mode = Type(); if (count >= next && values[next].fAttribute == FATTR4_MODE) { - st->st_mode |= values[next].fData.fValue32; + fAttrCache.st_mode |= values[next].fData.fValue32; next++; } else { // Try to guess using ACCESS request @@ -538,70 +580,76 @@ Inode::Stat(struct stat* st) return result; if ((prvl & ACCESS4_READ) != 0) - st->st_mode |= S_IRUSR | S_IRGRP | S_IROTH; + fAttrCache.st_mode |= S_IRUSR | S_IRGRP | S_IROTH; if ((prvl & ACCESS4_MODIFY) != 0) - st->st_mode |= S_IWUSR | S_IWGRP | S_IWOTH; + fAttrCache.st_mode |= S_IWUSR | S_IWGRP | S_IWOTH; if (fType == NF4DIR && (prvl & ACCESS4_LOOKUP) != 0) - st->st_mode |= S_IXUSR | S_IXGRP | S_IXOTH; + fAttrCache.st_mode |= S_IXUSR | S_IXGRP | S_IXOTH; if (fType != NF4DIR && (prvl & ACCESS4_EXECUTE) != 0) - st->st_mode |= S_IXUSR | S_IXGRP | S_IXOTH; + fAttrCache.st_mode |= S_IXUSR | S_IXGRP | S_IXOTH; } if (count >= next && values[next].fAttribute == FATTR4_NUMLINKS) { - st->st_nlink = values[next].fData.fValue32; + fAttrCache.st_nlink = values[next].fData.fValue32; next++; } else - st->st_nlink = 1; + fAttrCache.st_nlink = 1; if (count >= next && values[next].fAttribute == FATTR4_OWNER) { char* owner = reinterpret_cast(values[next].fData.fPointer); if (owner != NULL && isdigit(owner[0])) - st->st_uid = atoi(owner); + fAttrCache.st_uid = atoi(owner); else - st->st_uid = gIdMapper->GetUserId(owner); + fAttrCache.st_uid = gIdMapper->GetUserId(owner); next++; } else - st->st_uid = 0; + fAttrCache.st_uid = 0; if (count >= next && values[next].fAttribute == FATTR4_OWNER_GROUP) { char* group = reinterpret_cast(values[next].fData.fPointer); if (group != NULL && isdigit(group[0])) - st->st_gid = atoi(group); + fAttrCache.st_gid = atoi(group); else - st->st_gid = gIdMapper->GetGroupId(group); + fAttrCache.st_gid = gIdMapper->GetGroupId(group); next++; } else - st->st_gid = 0; + fAttrCache.st_gid = 0; if (count >= next && values[next].fAttribute == FATTR4_TIME_ACCESS) { - memcpy(&st->st_atim, values[next].fData.fPointer, sizeof(timespec)); - next++; - } else - memset(&st->st_atim, 0, sizeof(timespec)); - - if (count >= next && values[next].fAttribute == FATTR4_TIME_CREATE) { - memcpy(&st->st_crtim, values[next].fData.fPointer, + memcpy(&fAttrCache.st_atim, values[next].fData.fPointer, sizeof(timespec)); next++; } else - memset(&st->st_crtim, 0, sizeof(timespec)); + memset(&fAttrCache.st_atim, 0, sizeof(timespec)); + + if (count >= next && values[next].fAttribute == FATTR4_TIME_CREATE) { + memcpy(&fAttrCache.st_crtim, values[next].fData.fPointer, + sizeof(timespec)); + next++; + } else + memset(&fAttrCache.st_crtim, 0, sizeof(timespec)); if (count >= next && values[next].fAttribute == FATTR4_TIME_METADATA) { - memcpy(&st->st_ctim, values[next].fData.fPointer, sizeof(timespec)); + memcpy(&fAttrCache.st_ctim, values[next].fData.fPointer, + sizeof(timespec)); next++; } else - memset(&st->st_ctim, 0, sizeof(timespec)); + memset(&fAttrCache.st_ctim, 0, sizeof(timespec)); if (count >= next && values[next].fAttribute == FATTR4_TIME_MODIFY) { - memcpy(&st->st_mtim, values[next].fData.fPointer, sizeof(timespec)); + memcpy(&fAttrCache.st_mtim, values[next].fData.fPointer, + sizeof(timespec)); next++; } else - memset(&st->st_mtim, 0, sizeof(timespec)); + memset(&fAttrCache.st_mtim, 0, sizeof(timespec)); delete[] values; + + fAttrCacheExpire = time(NULL) + kAttrCacheExpirationTime; + return B_OK; } while (true); } @@ -701,9 +749,14 @@ Inode::WriteStat(const struct stat* st, uint32 mask) delete cookie; } - return result; + if (result != B_OK) + return result; + + break; } while (true); + _UpdateAttrCache(true); + 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 91751bb91e..9ca2466879 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -89,6 +89,12 @@ protected: static inline ino_t _FileIdToInoT(uint64 fileid); + struct stat fAttrCache; + mutex fAttrCacheLock; + time_t fAttrCacheExpire; + static const time_t kAttrCacheExpirationTime = 60; + status_t _UpdateAttrCache(bool force = false); + uint32 fType; FileInfo fInfo; diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp b/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp index 5f3c25c77b..47d6f8766b 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp @@ -109,6 +109,8 @@ Inode::OpenDir(OpenDirCookie* cookie) cookie->fCookie = 0; cookie->fCookieVerf = 2; + fFileSystem->Root()->MakeInfoInvalid(); + return B_OK; } while (true); } diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp index 9ecb03a239..9c7c83d491 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp @@ -15,6 +15,7 @@ #include "IdMap.h" #include "Request.h" +#include "RootInode.h" status_t @@ -172,6 +173,7 @@ Inode::Create(const char* name, int mode, int perms, OpenFileCookie* cookie, } while (true); fFileSystem->AddOpenFile(cookie); + fFileSystem->Root()->MakeInfoInvalid(); if (confirm) return _ConfirmOpen(fh, cookie); @@ -430,6 +432,8 @@ Inode::Write(OpenFileCookie* cookie, off_t pos, const void* _buffer, *_length = size; + fFileSystem->Root()->MakeInfoInvalid(); + return B_OK; } diff --git a/src/add-ons/kernel/file_systems/nfs4/RootInode.cpp b/src/add-ons/kernel/file_systems/nfs4/RootInode.cpp index d5830cea7d..82a0340400 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RootInode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RootInode.cpp @@ -14,9 +14,44 @@ #include "Request.h" +RootInode::RootInode() + : + fInfoCacheExpire(0) +{ + mutex_init(&fInfoCacheLock, NULL); +} + + +RootInode::~RootInode() +{ + mutex_destroy(&fInfoCacheLock); +} + + status_t RootInode::ReadInfo(struct fs_info* info) { + status_t result = _UpdateInfo(); + if (result != B_OK) + return result; + + memcpy(info, &fInfoCache, sizeof(struct fs_info)); + + return B_OK; +} + + +status_t +RootInode::_UpdateInfo(bool force) +{ + if (!force && fInfoCacheExpire > time(NULL)) + return B_OK; + + MutexLocker _(fInfoCacheLock); + + if (fInfoCacheExpire > time(NULL)) + return B_OK; + do { RPC::Server* serv = fFileSystem->Server(); Request request(serv); @@ -46,12 +81,12 @@ RootInode::ReadInfo(struct fs_info* info) return result; if (count >= next && values[next].fAttribute == FATTR4_FILES_FREE) { - info->free_nodes = values[next].fData.fValue64; + fInfoCache.free_nodes = values[next].fData.fValue64; next++; } if (count >= next && values[next].fAttribute == FATTR4_FILES_TOTAL) { - info->total_nodes = values[next].fData.fValue64; + fInfoCache.total_nodes = values[next].fData.fValue64; next++; } @@ -68,16 +103,16 @@ RootInode::ReadInfo(struct fs_info* info) if (io_size == LONGLONG_MAX) io_size = 32768; - info->io_size = io_size; - info->block_size = io_size; + fInfoCache.io_size = io_size; + fInfoCache.block_size = io_size; if (count >= next && values[next].fAttribute == FATTR4_SPACE_FREE) { - info->free_blocks = values[next].fData.fValue64 / io_size; + fInfoCache.free_blocks = values[next].fData.fValue64 / io_size; next++; } if (count >= next && values[next].fAttribute == FATTR4_SPACE_TOTAL) { - info->total_blocks = values[next].fData.fValue64 / io_size; + fInfoCache.total_blocks = values[next].fData.fValue64 / io_size; next++; } @@ -86,8 +121,10 @@ RootInode::ReadInfo(struct fs_info* info) break; } while (true); - info->flags = 0; - strncpy(info->volume_name, fInfo.fName, B_FILE_NAME_LENGTH); + fInfoCache.flags = 0; + strncpy(fInfoCache.volume_name, fInfo.fName, B_FILE_NAME_LENGTH); + + fInfoCacheExpire = time(NULL) + kAttrCacheExpirationTime; return B_OK; } diff --git a/src/add-ons/kernel/file_systems/nfs4/RootInode.h b/src/add-ons/kernel/file_systems/nfs4/RootInode.h index c2101875e8..5b01b89ff5 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RootInode.h +++ b/src/add-ons/kernel/file_systems/nfs4/RootInode.h @@ -16,13 +16,31 @@ class RootInode : public Inode { public: - status_t ReadInfo(struct fs_info* info); + RootInode(); + ~RootInode(); - bool ProbeMigration(); - status_t GetLocations(AttrValue** attr); + status_t ReadInfo(struct fs_info* info); + inline void MakeInfoInvalid(); + + bool ProbeMigration(); + status_t GetLocations(AttrValue** attr); + +private: + struct fs_info fInfoCache; + mutex fInfoCacheLock; + time_t fInfoCacheExpire; + + status_t _UpdateInfo(bool force = false); }; +inline void +RootInode::MakeInfoInvalid() +{ + fInfoCacheExpire = 0; +} + + #endif // ROOTINODE_H From 9cd76686f17b2ba8a1b0498a534d3a46e1fab541 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Tue, 10 Jul 2012 21:31:11 +0200 Subject: [PATCH 134/252] nfs4: Make Inode::Access() use cached attributes --- .../kernel/file_systems/nfs4/Inode.cpp | 86 ++++++++++++------- 1 file changed, 57 insertions(+), 29 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index 181ef37ca6..1614cb754f 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -445,48 +445,76 @@ Inode::ReadLink(void* buffer, size_t* length) status_t Inode::Access(int mode) { - do { - RPC::Server* serv = fFileSystem->Server(); - Request request(serv); - RequestBuilder& req = request.Builder(); + int acc = 0; - req.PutFH(fInfo.fHandle); - req.Access(); - - status_t result = request.Send(); + if (fFileSystem->IsAttrSupported(FATTR4_MODE)) { + status_t result = _UpdateAttrCache(); if (result != B_OK) return result; - ReplyInterpreter& reply = request.Reply(); + // Root squashing and owner mapping problems may make this function + // return false values. However, since due to race condition it can + // not be used for anything critical, it is not a serius problem. - if (_HandleErrors(reply.NFS4Error(), serv)) - continue; + mode_t nodeMode = fAttrCache.st_mode; + uint8 userMode = (nodeMode & S_IRWXU) >> 6; + uint8 groupMode = (nodeMode & S_IRWXG) >> 3; + uint8 otherMode = (nodeMode & S_IRWXO); - reply.PutFH(); + uid_t uid = geteuid(); + if (uid == 0) + acc = userMode | groupMode | otherMode | R_OK | W_OK; + else if (uid == fAttrCache.st_uid) + acc = userMode; + else if (getegid() == fAttrCache.st_gid) + acc = groupMode; + else + acc = otherMode; + } else { + do { + RPC::Server* serv = fFileSystem->Server(); + Request request(serv); + RequestBuilder& req = request.Builder(); - uint32 allowed; - result = reply.Access(NULL, &allowed); - if (result != B_OK) - return result; + req.PutFH(fInfo.fHandle); + req.Access(); - int acc = 0; - if ((allowed & ACCESS4_READ) != 0) - acc |= R_OK; + status_t result = request.Send(); + if (result != B_OK) + return result; - if (fType == NF4DIR && (allowed & ACCESS4_LOOKUP) != 0) - acc |= X_OK | R_OK; + ReplyInterpreter& reply = request.Reply(); - if (fType != NF4DIR && (allowed & ACCESS4_EXECUTE) != 0) - acc |= X_OK; + if (_HandleErrors(reply.NFS4Error(), serv)) + continue; - if ((allowed & ACCESS4_MODIFY) != 0) - acc |= W_OK; + reply.PutFH(); - if ((mode & acc) != mode) - return B_NOT_ALLOWED; + uint32 allowed; + result = reply.Access(NULL, &allowed); + if (result != B_OK) + return result; - return B_OK; - } while (true); + if ((allowed & ACCESS4_READ) != 0) + acc |= R_OK; + + if (fType == NF4DIR && (allowed & ACCESS4_LOOKUP) != 0) + acc |= X_OK | R_OK; + + if (fType != NF4DIR && (allowed & ACCESS4_EXECUTE) != 0) + acc |= X_OK; + + if ((allowed & ACCESS4_MODIFY) != 0) + acc |= W_OK; + + break; + } while (true); + } + + if ((mode & acc) != mode) + return B_NOT_ALLOWED; + + return B_OK; } From c3b57e8e834b942e3df0b77199b66640e3c3cf67 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Wed, 11 Jul 2012 19:51:26 +0200 Subject: [PATCH 135/252] nfs4: Use IPPROTO_* instead of enum Transport --- .../kernel/file_systems/nfs4/Connection.cpp | 26 ++++++++++++------- .../kernel/file_systems/nfs4/Connection.h | 16 ++++-------- .../kernel/file_systems/nfs4/FileSystem.cpp | 7 +++-- .../kernel/file_systems/nfs4/RPCServer.cpp | 7 +---- .../kernel/file_systems/nfs4/RPCServer.h | 3 +-- .../kernel/file_systems/nfs4/Request.cpp | 4 +-- .../file_systems/nfs4/kernel_interface.cpp | 8 ++++-- 7 files changed, 34 insertions(+), 37 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Connection.cpp b/src/add-ons/kernel/file_systems/nfs4/Connection.cpp index f7381c747f..20e1c93ba2 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Connection.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Connection.cpp @@ -54,7 +54,7 @@ status_t ServerAddress::ResolveName(const char* name, ServerAddress* addr) { addr->fPort = 2049; - addr->fProtocol = ProtocolUDP; + addr->fProtocol = IPPROTO_UDP; struct in_addr iaddr; if (inet_aton(name, &iaddr) != 0) { @@ -86,7 +86,7 @@ ServerAddress::ResolveName(const char* name, ServerAddress* addr) } -Connection::Connection(const sockaddr_in& addr, Transport proto) +Connection::Connection(const sockaddr_in& addr, int proto) : fWaitCancel(create_sem(0, NULL)), fSock(-1), @@ -97,14 +97,14 @@ Connection::Connection(const sockaddr_in& addr, Transport proto) } -ConnectionStream::ConnectionStream(const sockaddr_in& addr, Transport proto) +ConnectionStream::ConnectionStream(const sockaddr_in& addr, int proto) : Connection(addr, proto) { } -ConnectionPacket::ConnectionPacket(const sockaddr_in& addr, Transport proto) +ConnectionPacket::ConnectionPacket(const sockaddr_in& addr, int proto) : Connection(addr, proto) { @@ -323,10 +323,16 @@ Connection::Connect(Connection **pconn, const ServerAddress& id) addr.sin_port = htons(id.fPort); Connection* conn; - if (id.fProtocol == ProtocolTCP) - conn = new(std::nothrow) ConnectionStream(addr, id.fProtocol); - else - conn = new(std::nothrow) ConnectionPacket(addr, id.fProtocol); + switch (id.fProtocol) { + case IPPROTO_TCP: + conn = new(std::nothrow) ConnectionStream(addr, id.fProtocol); + break; + case IPPROTO_UDP: + conn = new(std::nothrow) ConnectionPacket(addr, id.fProtocol); + break; + default: + return B_BAD_VALUE; + } if (conn == NULL) return B_NO_MEMORY; @@ -346,10 +352,10 @@ status_t Connection::_Connect() { switch (fProtocol) { - case ProtocolTCP: + case IPPROTO_TCP: fSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); break; - case ProtocolUDP: + case IPPROTO_UDP: fSock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); break; default: diff --git a/src/add-ons/kernel/file_systems/nfs4/Connection.h b/src/add-ons/kernel/file_systems/nfs4/Connection.h index eff2a6673f..2386f76715 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Connection.h +++ b/src/add-ons/kernel/file_systems/nfs4/Connection.h @@ -15,15 +15,10 @@ #include -enum Transport { - ProtocolTCP = 6, - ProtocolUDP = 11 -}; - struct ServerAddress { uint32 fAddress; uint16 fPort; - Transport fProtocol; + int fProtocol; bool operator==(const ServerAddress& x); bool operator<(const ServerAddress& x); @@ -49,22 +44,21 @@ public: void Disconnect(); protected: - Connection(const sockaddr_in& addr, - Transport proto); + Connection(const sockaddr_in& addr, int proto); status_t _Connect(); sem_id fWaitCancel; int fSock; mutex fSockLock; - const Transport fProtocol; + const int fProtocol; const sockaddr_in fServerAddress; }; class ConnectionStream : public Connection { public: ConnectionStream(const sockaddr_in& addr, - Transport proto); + int proto); virtual status_t Send(const void* buffer, uint32 size); virtual status_t Receive(void** buffer, uint32* size); @@ -73,7 +67,7 @@ public: class ConnectionPacket : public Connection { public: ConnectionPacket(const sockaddr_in& addr, - Transport proto); + int proto); virtual status_t Send(const void* buffer, uint32 size); virtual status_t Receive(void** buffer, uint32* size); diff --git a/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp b/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp index a8ab9d4f67..95e95ae2f0 100644 --- a/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp @@ -215,16 +215,15 @@ FileSystem::Migrate(const RPC::Server* serv) reinterpret_cast(values[0].fData.fLocations); RPC::Server* server = fServer; + ServerAddress addr = fServer->ID(); for (uint32 i = 0; i < locs->fCount; i++) { for (uint32 j = 0; j < locs->fLocations[i].fCount; j++) { - ServerAddress addr; - if (ServerAddress::ResolveName(locs->fLocations[i].fLocations[j], &addr) != B_OK) continue; - if (gRPCServerManager->Acquire(&fServer, addr.fAddress, addr.fPort, - addr.fProtocol, CreateNFS4Server) == B_OK) { + if (gRPCServerManager->Acquire(&fServer, addr, + CreateNFS4Server) == B_OK) { free(const_cast(fPath)); fPath = strdup(locs->fLocations[i].fRootPath); diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp b/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp index 5e017149ad..cf913d39ff 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp @@ -279,16 +279,11 @@ ServerManager::~ServerManager() status_t -ServerManager::Acquire(Server** pserv, uint32 ip, uint16 port, Transport proto, +ServerManager::Acquire(Server** pserv, const ServerAddress& id, ProgramData* (*createPriv)(Server*)) { status_t result; - ServerAddress id; - id.fAddress = ip; - id.fPort = port; - id.fProtocol = proto; - MutexLocker locker(fLock); ServerNode* node = _Find(id); if (node != NULL) { diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCServer.h b/src/add-ons/kernel/file_systems/nfs4/RPCServer.h index 4d622d9905..3a4a7edd46 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RPCServer.h +++ b/src/add-ons/kernel/file_systems/nfs4/RPCServer.h @@ -160,8 +160,7 @@ public: ServerManager(); ~ServerManager(); - status_t Acquire(Server** pserv, uint32 ip, uint16 port, - Transport proto, + status_t Acquire(Server** pserv, const ServerAddress& id, ProgramData* (*createPriv)(Server*)); void Release(Server* serv); diff --git a/src/add-ons/kernel/file_systems/nfs4/Request.cpp b/src/add-ons/kernel/file_systems/nfs4/Request.cpp index 9e39a36b05..5262341889 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Request.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Request.cpp @@ -15,8 +15,8 @@ status_t Request::Send(Cookie* cookie) { switch (fServer->ID().fProtocol) { - case ProtocolUDP: return _SendUDP(cookie); - case ProtocolTCP: return _SendTCP(cookie); + case IPPROTO_UDP: return _SendUDP(cookie); + case IPPROTO_TCP: return _SendTCP(cookie); } return B_BAD_VALUE; 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 223bb6279d..b497f6e07f 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -80,9 +80,13 @@ nfs4_mount(fs_volume* volume, const char* device, uint32 flags, if (result != B_OK) return result; + ServerAddress id; + id.fAddress = ip; + id.fPort = 2049; + id.fProtocol = IPPROTO_UDP; + RPC::Server *server; - result = gRPCServerManager->Acquire(&server, ip, 2049, ProtocolUDP, - CreateNFS4Server); + result = gRPCServerManager->Acquire(&server, id, CreateNFS4Server); if (result != B_OK) return result; From 2e115f468fd39e9d5b8fd6771642cf49f24bccdd Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Wed, 11 Jul 2012 21:05:50 +0200 Subject: [PATCH 136/252] nfs4: Fix issues with renewal thread --- src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp | 12 ++++++++++-- src/add-ons/kernel/file_systems/nfs4/NFS4Server.h | 5 +++-- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp index 2ed40353b6..f3ea764525 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp @@ -16,7 +16,7 @@ NFS4Server::NFS4Server(RPC::Server* serv) : fThreadCancel(true), - fWaitCancel(create_sem(1, NULL)), + fWaitCancel(create_sem(0, NULL)), fLeaseTime(0), fClientIdLastUse(0), fUseCount(0), @@ -25,6 +25,8 @@ NFS4Server::NFS4Server(RPC::Server* serv) { mutex_init(&fClientIdLock, NULL); mutex_init(&fFSLock, NULL); + mutex_init(&fThreadStartLock, NULL); + } @@ -39,6 +41,7 @@ NFS4Server::~NFS4Server() delete_sem(fWaitCancel); mutex_destroy(&fClientIdLock); mutex_destroy(&fFSLock); + mutex_destroy(&fThreadStartLock); } @@ -166,7 +169,7 @@ NFS4Server::AddFileSystem(FileSystem* fs) fFileSystems->fPrev = fs; fFileSystems = fs; fUseCount += fs->OpenFilesCount(); - if (fs->OpenFilesCount() > 0 && fThreadCancel) + if (fs->OpenFilesCount() > 0) _StartRenewing(); } @@ -274,6 +277,11 @@ NFS4Server::_GetLeaseTime() status_t NFS4Server::_StartRenewing() { + if (!fThreadCancel) + return B_OK; + + MutexLocker _(fThreadStartLock); + if (!fThreadCancel) return B_OK; diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h index 210e3fa153..46134e8b1b 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h @@ -43,9 +43,11 @@ private: status_t _StartRenewing(); status_t _Renewal(); static status_t _RenewalThreadStart(void* ptr); + thread_id fThread; bool fThreadCancel; sem_id fWaitCancel; + mutex fThreadStartLock; uint32 fLeaseTime; @@ -67,8 +69,7 @@ NFS4Server::IncUsage() { MutexLocker _(fFSLock); fUseCount++; - if (fThreadCancel) - _StartRenewing(); + _StartRenewing(); fClientIdLastUse = time(NULL); } From 367b07d54addf471636a7c5dc1bde320560c4f68 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Wed, 11 Jul 2012 22:06:03 +0200 Subject: [PATCH 137/252] nfs4: Use more meaningful names in Connection and RPCServer --- .../kernel/file_systems/nfs4/Connection.cpp | 140 +++++++++--------- .../kernel/file_systems/nfs4/Connection.h | 31 ++-- .../kernel/file_systems/nfs4/RPCServer.cpp | 56 +++---- .../kernel/file_systems/nfs4/RPCServer.h | 28 ++-- 4 files changed, 129 insertions(+), 126 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Connection.cpp b/src/add-ons/kernel/file_systems/nfs4/Connection.cpp index 20e1c93ba2..10b576cced 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Connection.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Connection.cpp @@ -24,41 +24,41 @@ bool -ServerAddress::operator==(const ServerAddress& x) +ServerAddress::operator==(const ServerAddress& address) { - return fAddress == x.fAddress && fPort == x.fPort - && fProtocol == x.fProtocol; + return fAddress == address.fAddress && fPort == address.fPort + && fProtocol == address.fProtocol; } bool -ServerAddress::operator<(const ServerAddress& x) +ServerAddress::operator<(const ServerAddress& address) { - return fAddress < x.fAddress || - (fAddress == x.fAddress && fPort < x.fPort) || - (fAddress == x.fAddress && fPort == x.fPort && - fProtocol < x.fProtocol); + return fAddress < address.fAddress || + (fAddress == address.fAddress && fPort < address.fPort) || + (fAddress == address.fAddress && fPort == address.fPort && + fProtocol < address.fProtocol); } ServerAddress& -ServerAddress::operator=(const ServerAddress& x) +ServerAddress::operator=(const ServerAddress& address) { - fAddress = x.fAddress; - fPort = x.fPort; - fProtocol = x.fProtocol; + fAddress = address.fAddress; + fPort = address.fPort; + fProtocol = address.fProtocol; return *this; } status_t -ServerAddress::ResolveName(const char* name, ServerAddress* addr) +ServerAddress::ResolveName(const char* name, ServerAddress* address) { - addr->fPort = 2049; - addr->fProtocol = IPPROTO_UDP; + address->fPort = 2049; + address->fProtocol = IPPROTO_UDP; struct in_addr iaddr; if (inet_aton(name, &iaddr) != 0) { - addr->fAddress = ntohl(iaddr.s_addr); + address->fAddress = ntohl(iaddr.s_addr); return B_OK; } @@ -70,9 +70,10 @@ ServerAddress::ResolveName(const char* name, ServerAddress* addr) addrinfo* current = ai; while (current != NULL) { if (current->ai_family == AF_INET) { - sockaddr_in* sin = reinterpret_cast(current->ai_addr); + sockaddr_in* sin = + reinterpret_cast(current->ai_addr); - addr->fAddress = ntohl(sin->sin_addr.s_addr); + address->fAddress = ntohl(sin->sin_addr.s_addr); freeaddrinfo(ai); return B_OK; @@ -86,52 +87,52 @@ ServerAddress::ResolveName(const char* name, ServerAddress* addr) } -Connection::Connection(const sockaddr_in& addr, int proto) +Connection::Connection(const sockaddr_in& address, int protocol) : fWaitCancel(create_sem(0, NULL)), - fSock(-1), - fProtocol(proto), - fServerAddress(addr) + fSocket(-1), + fProtocol(protocol), + fServerAddress(address) { - mutex_init(&fSockLock, NULL); + mutex_init(&fSocketLock, NULL); } -ConnectionStream::ConnectionStream(const sockaddr_in& addr, int proto) +ConnectionStream::ConnectionStream(const sockaddr_in& address, int protocol) : - Connection(addr, proto) + Connection(address, protocol) { } -ConnectionPacket::ConnectionPacket(const sockaddr_in& addr, int proto) +ConnectionPacket::ConnectionPacket(const sockaddr_in& address, int protocol) : - Connection(addr, proto) + Connection(address, protocol) { } Connection::~Connection() { - if (fSock != -1) - close(fSock); - mutex_destroy(&fSockLock); + if (fSocket != -1) + close(fSocket); + mutex_destroy(&fSocketLock); delete_sem(fWaitCancel); } status_t -Connection::GetLocalID(ServerAddress* addr) +Connection::GetLocalAddress(ServerAddress* address) { struct sockaddr_in saddr; - socklen_t slen = sizeof(addr); - status_t result = getsockname(fSock, (struct sockaddr*)&saddr, &slen); + socklen_t slen = sizeof(saddr); + status_t result = getsockname(fSocket, (struct sockaddr*)&saddr, &slen); if (result != B_OK) return result; - addr->fProtocol = fProtocol; - addr->fPort = ntohs(saddr.sin_port); - addr->fAddress = ntohl(saddr.sin_addr.s_addr); + address->fProtocol = fProtocol; + address->fPort = ntohs(saddr.sin_port); + address->fAddress = ntohl(saddr.sin_addr.s_addr); return B_OK; } @@ -152,12 +153,12 @@ ConnectionStream::Send(const void* buffer, uint32 size) // More than one threads may send data and ksend is allowed to send partial // data. Need a lock here. uint32 sent = 0; - mutex_lock(&fSockLock); + mutex_lock(&fSocketLock); do { - result = send(fSock, buf + sent, size + sizeof(uint32) - sent, 0); + result = send(fSocket, buf + sent, size + sizeof(uint32) - sent, 0); sent += result; } while (result > 0 && sent < size + sizeof(uint32)); - mutex_unlock(&fSockLock); + mutex_unlock(&fSocketLock); if (result < 0) { result = errno; free(buf); @@ -176,7 +177,7 @@ status_t ConnectionPacket::Send(const void* buffer, uint32 size) { // send on DGRAM sockets is atomic. No need to lock. - status_t result = send(fSock, buffer, size, 0); + status_t result = send(fSocket, buffer, size, 0); if (result < 0) return errno; @@ -185,7 +186,7 @@ ConnectionPacket::Send(const void* buffer, uint32 size) status_t -ConnectionStream::Receive(void** pbuffer, uint32* psize) +ConnectionStream::Receive(void** _buffer, uint32* _size) { status_t result; @@ -200,7 +201,7 @@ ConnectionStream::Receive(void** pbuffer, uint32* psize) object[0].type = B_OBJECT_TYPE_SEMAPHORE; object[0].events = B_EVENT_ACQUIRE_SEMAPHORE; - object[1].object = fSock; + object[1].object = fSocket; object[1].type = B_OBJECT_TYPE_FD; object[1].events = B_EVENT_READ; @@ -216,7 +217,7 @@ ConnectionStream::Receive(void** pbuffer, uint32* psize) // There is only one listener thread per connection. No need to lock. uint32 received = 0; do { - result = recv(fSock, &record_size + received, + result = recv(fSocket, &record_size + received, sizeof(record_size) - received, 0); received += result; } while (result > 0 && received < sizeof(record_size)); @@ -242,7 +243,7 @@ ConnectionStream::Receive(void** pbuffer, uint32* psize) received = 0; do { - result = recv(fSock, (uint8*)buffer + size + received, + result = recv(fSocket, (uint8*)buffer + size + received, record_size - received, 0); received += result; } while (result > 0 && received < sizeof(record_size)); @@ -256,15 +257,15 @@ ConnectionStream::Receive(void** pbuffer, uint32* psize) } while (!last_one); - *pbuffer = buffer; - *psize = size; + *_buffer = buffer; + *_size = size; return B_OK; } status_t -ConnectionPacket::Receive(void** pbuffer, uint32* psize) +ConnectionPacket::Receive(void** _buffer, uint32* _size) { status_t result; int32 size = MAX_PACKET_SIZE; @@ -278,7 +279,7 @@ ConnectionPacket::Receive(void** pbuffer, uint32* psize) object[0].type = B_OBJECT_TYPE_SEMAPHORE; object[0].events = B_EVENT_ACQUIRE_SEMAPHORE; - object[1].object = fSock; + object[1].object = fSocket; object[1].type = B_OBJECT_TYPE_FD; object[1].events = B_EVENT_READ; @@ -294,7 +295,7 @@ ConnectionPacket::Receive(void** pbuffer, uint32* psize) } while (true); // There is only one listener thread per connection. No need to lock. - size = recv(fSock, buffer, size, 0); + size = recv(fSocket, buffer, size, 0); if (size < 0) { result = errno; free(buffer); @@ -304,31 +305,31 @@ ConnectionPacket::Receive(void** pbuffer, uint32* psize) return ECONNABORTED; } - *pbuffer = buffer; - *psize = size; + *_buffer = buffer; + *_size = size; return B_OK; } status_t -Connection::Connect(Connection **pconn, const ServerAddress& id) +Connection::Connect(Connection **_connection, const ServerAddress& address) { struct sockaddr_in addr; memset(&addr, 0, sizeof(addr)); addr.sin_len = sizeof(struct sockaddr_in); addr.sin_family = AF_INET; - addr.sin_addr.s_addr = htonl(id.fAddress); - addr.sin_port = htons(id.fPort); + addr.sin_addr.s_addr = htonl(address.fAddress); + addr.sin_port = htons(address.fPort); Connection* conn; - switch (id.fProtocol) { + switch (address.fProtocol) { case IPPROTO_TCP: - conn = new(std::nothrow) ConnectionStream(addr, id.fProtocol); + conn = new(std::nothrow) ConnectionStream(addr, address.fProtocol); break; case IPPROTO_UDP: - conn = new(std::nothrow) ConnectionPacket(addr, id.fProtocol); + conn = new(std::nothrow) ConnectionPacket(addr, address.fProtocol); break; default: return B_BAD_VALUE; @@ -336,39 +337,39 @@ Connection::Connect(Connection **pconn, const ServerAddress& id) if (conn == NULL) return B_NO_MEMORY; - status_t result = conn->_Connect(); + status_t result = conn->Connect(); if (result != B_OK) { delete conn; return result; } - *pconn = conn; + *_connection = conn; return B_OK; } status_t -Connection::_Connect() +Connection::Connect() { switch (fProtocol) { case IPPROTO_TCP: - fSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + fSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); break; case IPPROTO_UDP: - fSock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + fSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); break; default: return B_BAD_VALUE; } - if (fSock < 0) + if (fSocket < 0) return errno; - status_t result = connect(fSock, (struct sockaddr*)&fServerAddress, + status_t result = connect(fSocket, (struct sockaddr*)&fServerAddress, fServerAddress.sin_len); if (result < 0) { result = errno; - close(fSock); + close(fSocket); return result; } @@ -380,9 +381,9 @@ status_t Connection::Reconnect() { release_sem(fWaitCancel); - close(fSock); + close(fSocket); acquire_sem(fWaitCancel); - return _Connect(); + return Connect(); } @@ -391,8 +392,7 @@ Connection::Disconnect() { release_sem(fWaitCancel); - int sock = fSock; - fSock = -1; - close(sock); + close(fSocket); + fSocket = -1; } diff --git a/src/add-ons/kernel/file_systems/nfs4/Connection.h b/src/add-ons/kernel/file_systems/nfs4/Connection.h index 2386f76715..d6f996a04d 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Connection.h +++ b/src/add-ons/kernel/file_systems/nfs4/Connection.h @@ -20,36 +20,37 @@ struct ServerAddress { uint16 fPort; int fProtocol; - bool operator==(const ServerAddress& x); - bool operator<(const ServerAddress& x); + bool operator==(const ServerAddress& address); + bool operator<(const ServerAddress& address); - ServerAddress& operator=(const ServerAddress& x); + ServerAddress& operator=(const ServerAddress& address); static status_t ResolveName(const char* name, - ServerAddress* addr); + ServerAddress* address); }; class Connection { public: - static status_t Connect(Connection **conn, - const ServerAddress& id); + static status_t Connect(Connection **connection, + const ServerAddress& address); virtual ~Connection(); virtual status_t Send(const void* buffer, uint32 size) = 0; virtual status_t Receive(void** buffer, uint32* size) = 0; - status_t GetLocalID(ServerAddress* addr); + status_t GetLocalAddress(ServerAddress* address); status_t Reconnect(); void Disconnect(); protected: - Connection(const sockaddr_in& addr, int proto); - status_t _Connect(); + Connection(const sockaddr_in& address, + int protocol); + status_t Connect(); sem_id fWaitCancel; - int fSock; - mutex fSockLock; + int fSocket; + mutex fSocketLock; const int fProtocol; const sockaddr_in fServerAddress; @@ -57,8 +58,8 @@ protected: class ConnectionStream : public Connection { public: - ConnectionStream(const sockaddr_in& addr, - int proto); + ConnectionStream(const sockaddr_in& address, + int protocol); virtual status_t Send(const void* buffer, uint32 size); virtual status_t Receive(void** buffer, uint32* size); @@ -66,8 +67,8 @@ public: class ConnectionPacket : public Connection { public: - ConnectionPacket(const sockaddr_in& addr, - int proto); + ConnectionPacket(const sockaddr_in& address, + int protocol); virtual status_t Send(const void* buffer, uint32 size); virtual status_t Receive(void** buffer, uint32* size); diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp b/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp index cf913d39ff..e13a36e276 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp @@ -35,14 +35,14 @@ RequestManager::~RequestManager() void -RequestManager::AddRequest(Request* req) +RequestManager::AddRequest(Request* request) { MutexLocker _(fLock); if (fQueueTail != NULL) - fQueueTail->fNext = req; + fQueueTail->fNext = request; else - fQueueHead = req; - fQueueTail = req; + fQueueHead = request; + fQueueTail = request; } @@ -72,10 +72,10 @@ RequestManager::FindRequest(uint32 xid) } -Server::Server(Connection* conn, ServerAddress* addr) +Server::Server(Connection* connection, ServerAddress* address) : - fConnection(conn), - fAddress(addr), + fConnection(connection), + fAddress(address), fPrivateData(NULL), fXID(rand() << 1) { @@ -164,19 +164,19 @@ Server::SendCallAsync(Call* call, Reply** reply, Request** request) status_t -Server::ResendCallAsync(Call* call, Request* req) +Server::ResendCallAsync(Call* call, Request* request) { if (fThreadError != B_OK) { - fRequests.FindRequest(req->fXID); - delete req; + fRequests.FindRequest(request->fXID); + delete request; return fThreadError; } XDR::WriteStream& stream = call->Stream(); status_t result = fConnection->Send(stream.Buffer(), stream.Size()); if (result != B_OK) { - fRequests.FindRequest(req->fXID); - delete req; + fRequests.FindRequest(request->fXID); + delete request; return result; } @@ -257,9 +257,9 @@ Server::_Listener() status_t -Server::_ListenerThreadStart(void* ptr) +Server::_ListenerThreadStart(void* object) { - Server* server = reinterpret_cast(ptr); + Server* server = reinterpret_cast(object); return server->_Listener(); } @@ -279,16 +279,16 @@ ServerManager::~ServerManager() status_t -ServerManager::Acquire(Server** pserv, const ServerAddress& id, - ProgramData* (*createPriv)(Server*)) +ServerManager::Acquire(Server** _server, const ServerAddress& address, + ProgramData* (*createPrivateData)(Server*)) { status_t result; MutexLocker locker(fLock); - ServerNode* node = _Find(id); + ServerNode* node = _Find(address); if (node != NULL) { node->fRefCount++; - *pserv = node->fServer; + *_server = node->fServer; return B_OK; } @@ -297,10 +297,10 @@ ServerManager::Acquire(Server** pserv, const ServerAddress& id, if (node == NULL) return B_NO_MEMORY; - node->fID = id; + node->fID = address; Connection* conn; - result = Connection::Connect(&conn, id); + result = Connection::Connect(&conn, address); if (result != B_OK) { delete node; return result; @@ -312,7 +312,7 @@ ServerManager::Acquire(Server** pserv, const ServerAddress& id, delete conn; return B_NO_MEMORY; } - node->fServer->SetPrivateData(createPriv(node->fServer)); + node->fServer->SetPrivateData(createPrivateData(node->fServer)); node->fRefCount = 1; node->fLeft = node->fRight = NULL; @@ -323,20 +323,20 @@ ServerManager::Acquire(Server** pserv, const ServerAddress& id, delete node->fServer; delete node; - *pserv = nd->fServer; + *_server = nd->fServer; return B_OK; } - *pserv = node->fServer; + *_server = node->fServer; return B_OK; } void -ServerManager::Release(Server* serv) +ServerManager::Release(Server* server) { MutexLocker _(fLock); - ServerNode* node = _Find(serv->ID()); + ServerNode* node = _Find(server->ID()); if (node != NULL) { node->fRefCount--; @@ -350,13 +350,13 @@ ServerManager::Release(Server* serv) ServerNode* -ServerManager::_Find(const ServerAddress& id) +ServerManager::_Find(const ServerAddress& address) { ServerNode* node = fRoot; while (node != NULL) { - if (node->fID == id) + if (node->fID == address) return node; - if (node->fID < id) + if (node->fID < address) node = node->fRight; else node = node->fLeft; diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCServer.h b/src/add-ons/kernel/file_systems/nfs4/RPCServer.h index 3a4a7edd46..3a954b35cd 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RPCServer.h +++ b/src/add-ons/kernel/file_systems/nfs4/RPCServer.h @@ -35,7 +35,7 @@ public: RequestManager(); ~RequestManager(); - void AddRequest(Request* req); + void AddRequest(Request* request); Request* FindRequest(uint32 xid); private: @@ -52,15 +52,17 @@ public: class Server { public: - Server(Connection* conn, - ServerAddress* addr); + Server(Connection* connection, + ServerAddress* address); virtual ~Server(); status_t SendCall(Call* call, Reply** reply); status_t SendCallAsync(Call* call, Reply** reply, Request** request); - status_t ResendCallAsync(Call* call, Request* req); + status_t ResendCallAsync(Call* call, + Request* request); + inline status_t WaitCall(Request* request, bigtime_t time = kWaitTime); inline status_t CancelCall(Request* request); @@ -72,7 +74,7 @@ public: inline ServerAddress LocalID() const; inline ProgramData* PrivateData(); - inline void SetPrivateData(ProgramData* priv); + inline void SetPrivateData(ProgramData* privateData); private: inline uint32 _GetXID(); @@ -80,7 +82,7 @@ private: status_t _StartListening(); status_t _Listener(); - static status_t _ListenerThreadStart(void* ptr); + static status_t _ListenerThreadStart(void* object); thread_id fThread; bool fThreadCancel; @@ -126,7 +128,7 @@ Server::LocalID() const { ServerAddress addr; memset(&addr, 0, sizeof(addr)); - fConnection->GetLocalID(&addr); + fConnection->GetLocalAddress(&addr); return addr; } @@ -139,10 +141,10 @@ Server::PrivateData() inline void -Server::SetPrivateData(ProgramData* priv) +Server::SetPrivateData(ProgramData* privateData) { delete fPrivateData; - fPrivateData = priv; + fPrivateData = privateData; } @@ -160,13 +162,13 @@ public: ServerManager(); ~ServerManager(); - status_t Acquire(Server** pserv, const ServerAddress& id, - ProgramData* (*createPriv)(Server*)); - void Release(Server* serv); + status_t Acquire(Server** _server, const ServerAddress& address, + ProgramData* (*createPrivateData)(Server*)); + void Release(Server* server); private: - ServerNode* _Find(const ServerAddress& id); + ServerNode* _Find(const ServerAddress& address); void _Delete(ServerNode* node); ServerNode* _Insert(ServerNode* node); From 137884e0d2fa9e53a17fa2b736b4a5c158b7c75f Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Thu, 12 Jul 2012 00:22:35 +0200 Subject: [PATCH 138/252] nfs4: Make networking code IP version agnostic --- .../kernel/file_systems/nfs4/Connection.cpp | 125 +++++++++++------- .../kernel/file_systems/nfs4/Connection.h | 17 +-- .../file_systems/nfs4/RequestBuilder.cpp | 77 +++++++++-- .../kernel/file_systems/nfs4/RequestBuilder.h | 4 +- .../file_systems/nfs4/kernel_interface.cpp | 20 +-- 5 files changed, 156 insertions(+), 87 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Connection.cpp b/src/add-ons/kernel/file_systems/nfs4/Connection.cpp index 10b576cced..17e41cf6c5 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Connection.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Connection.cpp @@ -19,6 +19,8 @@ #include +#define NFS4_PORT 2049 + #define LAST_FRAGMENT 0x80000000 #define MAX_PACKET_SIZE 65535 @@ -26,17 +28,15 @@ bool ServerAddress::operator==(const ServerAddress& address) { - return fAddress == address.fAddress && fPort == address.fPort - && fProtocol == address.fProtocol; + return memcmp(&fAddress, &address.fAddress, sizeof(fAddress)) == 0 + && fProtocol == address.fProtocol; } bool ServerAddress::operator<(const ServerAddress& address) { - return fAddress < address.fAddress || - (fAddress == address.fAddress && fPort < address.fPort) || - (fAddress == address.fAddress && fPort == address.fPort && - fProtocol < address.fProtocol); + int compare = memcmp(&fAddress, &address.fAddress, sizeof(fAddress)); + return compare < 0 || (compare == 0 && fProtocol < address.fProtocol); } @@ -44,21 +44,34 @@ ServerAddress& ServerAddress::operator=(const ServerAddress& address) { fAddress = address.fAddress; - fPort = address.fPort; fProtocol = address.fProtocol; return *this; } +ServerAddress::ServerAddress() + : + fProtocol(0) +{ + memset(&fAddress, 0, sizeof(fAddress)); +} + + status_t ServerAddress::ResolveName(const char* name, ServerAddress* address) { - address->fPort = 2049; address->fProtocol = IPPROTO_UDP; - struct in_addr iaddr; - if (inet_aton(name, &iaddr) != 0) { - address->fAddress = ntohl(iaddr.s_addr); + // getaddrinfo() is very expensive when called from kernel, so we do not + // want to call it unless there is no other choice. + + struct sockaddr_in addr; + memset(&addr, 0, sizeof(addr)); + if (inet_aton(name, &addr.sin_addr) == 1) { + addr.sin_family = AF_INET; + addr.sin_port = htons(NFS4_PORT); + + memcpy(&address->fAddress, &addr, sizeof(addr)); return B_OK; } @@ -70,16 +83,20 @@ ServerAddress::ResolveName(const char* name, ServerAddress* address) addrinfo* current = ai; while (current != NULL) { if (current->ai_family == AF_INET) { - sockaddr_in* sin = - reinterpret_cast(current->ai_addr); - - address->fAddress = ntohl(sin->sin_addr.s_addr); - - freeaddrinfo(ai); - return B_OK; + memcpy(&address->fAddress, current->ai_addr, sizeof(sockaddr_in)); + reinterpret_cast(&address->fAddress)->sin_port + = htons(NFS4_PORT); + } else if (current->ai_family == AF_INET6) { + memcpy(&address->fAddress, current->ai_addr, sizeof(sockaddr_in6)); + reinterpret_cast(&address->fAddress)->sin6_port + = htons(NFS4_PORT); + } else { + current = current->ai_next; + continue; } - current = current->ai_next; + freeaddrinfo(ai); + return B_OK; } freeaddrinfo(ai); @@ -87,27 +104,26 @@ ServerAddress::ResolveName(const char* name, ServerAddress* address) } -Connection::Connection(const sockaddr_in& address, int protocol) +Connection::Connection(const ServerAddress& address) : fWaitCancel(create_sem(0, NULL)), fSocket(-1), - fProtocol(protocol), fServerAddress(address) { mutex_init(&fSocketLock, NULL); } -ConnectionStream::ConnectionStream(const sockaddr_in& address, int protocol) +ConnectionStream::ConnectionStream(const ServerAddress& address) : - Connection(address, protocol) + Connection(address) { } -ConnectionPacket::ConnectionPacket(const sockaddr_in& address, int protocol) +ConnectionPacket::ConnectionPacket(const ServerAddress& address) : - Connection(address, protocol) + Connection(address) { } @@ -124,17 +140,22 @@ Connection::~Connection() status_t Connection::GetLocalAddress(ServerAddress* address) { - struct sockaddr_in saddr; - socklen_t slen = sizeof(saddr); - status_t result = getsockname(fSocket, (struct sockaddr*)&saddr, &slen); - if (result != B_OK) - return result; + address->fProtocol = fServerAddress.fProtocol; - address->fProtocol = fProtocol; - address->fPort = ntohs(saddr.sin_port); - address->fAddress = ntohl(saddr.sin_addr.s_addr); + socklen_t addressSize; + switch (reinterpret_cast(&fServerAddress)->sa_family) { + case AF_INET: + addressSize = sizeof(sockaddr_in); + break; + case AF_INET6: + addressSize = sizeof(sockaddr_in6); + break; + default: + return B_BAD_VALUE; + } - return B_OK; + return getsockname(fSocket, + (struct sockaddr*)&address->fAddress, &addressSize); } @@ -315,21 +336,13 @@ ConnectionPacket::Receive(void** _buffer, uint32* _size) status_t Connection::Connect(Connection **_connection, const ServerAddress& address) { - struct sockaddr_in addr; - - memset(&addr, 0, sizeof(addr)); - addr.sin_len = sizeof(struct sockaddr_in); - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = htonl(address.fAddress); - addr.sin_port = htons(address.fPort); - Connection* conn; switch (address.fProtocol) { case IPPROTO_TCP: - conn = new(std::nothrow) ConnectionStream(addr, address.fProtocol); + conn = new(std::nothrow) ConnectionStream(address); break; case IPPROTO_UDP: - conn = new(std::nothrow) ConnectionPacket(addr, address.fProtocol); + conn = new(std::nothrow) ConnectionPacket(address); break; default: return B_BAD_VALUE; @@ -352,12 +365,15 @@ Connection::Connect(Connection **_connection, const ServerAddress& address) status_t Connection::Connect() { - switch (fProtocol) { + const sockaddr& address = + *reinterpret_cast(&fServerAddress); + + switch (fServerAddress.fProtocol) { case IPPROTO_TCP: - fSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + fSocket = socket(address.sa_family, SOCK_STREAM, IPPROTO_TCP); break; case IPPROTO_UDP: - fSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + fSocket = socket(address.sa_family, SOCK_DGRAM, IPPROTO_UDP); break; default: return B_BAD_VALUE; @@ -365,8 +381,19 @@ Connection::Connect() if (fSocket < 0) return errno; - status_t result = connect(fSocket, (struct sockaddr*)&fServerAddress, - fServerAddress.sin_len); + socklen_t addressSize; + switch (address.sa_family) { + case AF_INET: + addressSize = sizeof(sockaddr_in); + break; + case AF_INET6: + addressSize = sizeof(sockaddr_in6); + break; + default: + return B_BAD_VALUE; + } + + status_t result = connect(fSocket, &address, addressSize); if (result < 0) { result = errno; close(fSocket); diff --git a/src/add-ons/kernel/file_systems/nfs4/Connection.h b/src/add-ons/kernel/file_systems/nfs4/Connection.h index d6f996a04d..2da2f6e5b2 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Connection.h +++ b/src/add-ons/kernel/file_systems/nfs4/Connection.h @@ -16,8 +16,7 @@ struct ServerAddress { - uint32 fAddress; - uint16 fPort; + sockaddr_storage fAddress; int fProtocol; bool operator==(const ServerAddress& address); @@ -25,6 +24,8 @@ struct ServerAddress { ServerAddress& operator=(const ServerAddress& address); + ServerAddress(); + static status_t ResolveName(const char* name, ServerAddress* address); }; @@ -44,22 +45,19 @@ public: void Disconnect(); protected: - Connection(const sockaddr_in& address, - int protocol); + Connection(const ServerAddress& address); status_t Connect(); sem_id fWaitCancel; int fSocket; mutex fSocketLock; - const int fProtocol; - const sockaddr_in fServerAddress; + const ServerAddress fServerAddress; }; class ConnectionStream : public Connection { public: - ConnectionStream(const sockaddr_in& address, - int protocol); + ConnectionStream(const ServerAddress& address); virtual status_t Send(const void* buffer, uint32 size); virtual status_t Receive(void** buffer, uint32* size); @@ -67,8 +65,7 @@ public: class ConnectionPacket : public Connection { public: - ConnectionPacket(const sockaddr_in& address, - int protocol); + ConnectionPacket(const ServerAddress& address); virtual status_t Send(const void* buffer, uint32 size); virtual status_t Receive(void** buffer, uint32* size); diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp index e9007fad0f..738f854d75 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp @@ -9,6 +9,7 @@ #include "RequestBuilder.h" +#include #include #include "Cookie.h" @@ -592,7 +593,7 @@ RequestBuilder::SetAttr(const uint32* id, uint32 stateSeq, AttrValue* attr, status_t -RequestBuilder::SetClientID(const RPC::Server* serv) +RequestBuilder::SetClientID(const RPC::Server* server) { if (fProcedure != ProcCompound) return B_BAD_VALUE; @@ -604,19 +605,9 @@ RequestBuilder::SetClientID(const RPC::Server* serv) verifier = verifier << 32 | rand(); fRequest->Stream().AddUHyper(verifier); - char id[128] = "HAIKU:kernel:"; - int pos = strlen(id); - *(uint32*)(id + pos) = serv->ID().fAddress; - pos += sizeof(uint32); - *(uint16*)(id + pos) = serv->ID().fPort; - pos += sizeof(uint16); - *(uint16*)(id + pos) = serv->ID().fProtocol; - pos += sizeof(uint16); - - *(uint32*)(id + pos) = serv->LocalID().fAddress; - pos += sizeof(uint32); - - fRequest->Stream().AddOpaque(id, pos); + status_t result = _GenerateClientId(fRequest->Stream(), server); + if (result != B_OK) + return result; // Callbacks are currently not supported fRequest->Stream().AddUInt(0); @@ -630,6 +621,64 @@ RequestBuilder::SetClientID(const RPC::Server* serv) } +status_t +RequestBuilder::_GenerateClientId(XDR::WriteStream& stream, + const RPC::Server* server) +{ + char id[512] = "HAIKU:kernel:"; + int pos = strlen(id); + + const sockaddr* remoteAddress = + reinterpret_cast(&server->ID().fAddress); + + ServerAddress local = server->LocalID(); + const sockaddr* localAddress = reinterpret_cast(&local.fAddress); + + const sockaddr_in* address4; + const sockaddr_in6* address6; + switch (remoteAddress->sa_family) { + case AF_INET: + address4 = reinterpret_cast(remoteAddress); + + memcpy(id + pos, &address4->sin_addr, sizeof(address4->sin_addr)); + pos += sizeof(address4->sin_addr); + + memcpy(id + pos, + &reinterpret_cast(localAddress)->sin_addr, + sizeof(address4->sin_addr)); + pos += sizeof(address4->sin_addr); + + *(uint16*)(id + pos) = address4->sin_port; + break; + + case AF_INET6: + address6 = reinterpret_cast(remoteAddress); + + memcpy(id + pos, &address6->sin6_addr, sizeof(address6->sin6_addr)); + pos += sizeof(address6->sin6_addr); + + memcpy(id + pos, + &reinterpret_cast(localAddress)->sin6_addr, + sizeof(address6->sin6_addr)); + pos += sizeof(address6->sin6_addr); + + *(uint16*)(id + pos) = address6->sin6_port; + break; + + default: + return B_BAD_VALUE; + } + pos += sizeof(uint16); + + *(uint16*)(id + pos) = server->ID().fProtocol; + pos += sizeof(uint16); + + stream.AddOpaque(id, pos); + + return B_OK; +} + + status_t RequestBuilder::SetClientIDConfirm(uint64 id, uint64 ver) { diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h index 753a8378bd..17800c9eca 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h @@ -68,7 +68,7 @@ public: status_t SaveFH(); status_t SetAttr(const uint32* id, uint32 stateSeq, AttrValue* attr, uint32 count); - status_t SetClientID(const RPC::Server* serv); + status_t SetClientID(const RPC::Server* server); status_t SetClientIDConfirm(uint64 id, uint64 ver); status_t Verify(AttrValue* attr, uint32 count); status_t Write(const uint32* id, uint32 stateSeq, @@ -85,6 +85,8 @@ private: void _GenerateLockOwner(XDR::WriteStream& stream, OpenFileCookie* cookie, LockOwner* owner); + status_t _GenerateClientId(XDR::WriteStream& stream, + const RPC::Server* server); void _EncodeAttrs(XDR::WriteStream& stream, AttrValue* attr, uint32 count); 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 b497f6e07f..fdd79f3d11 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -39,8 +39,10 @@ CreateNFS4Server(RPC::Server* serv) } + +// TODO: IPv6 address will cause problems static status_t -ParseArguments(const char* _args, uint32* _ip, char* _path) +ParseArguments(const char* _args, ServerAddress* address, char* _path) { if (_args == NULL) return B_BAD_VALUE; @@ -53,13 +55,10 @@ ParseArguments(const char* _args, uint32* _ip, char* _path) } *path++ = '\0'; - ServerAddress addr; - status_t result = ServerAddress::ResolveName(args, &addr); + status_t result = ServerAddress::ResolveName(args, address); if (result != B_OK) return result; - *_ip = addr.fAddress; - _path[255] = '\0'; strncpy(_path, path, 255); @@ -74,19 +73,14 @@ nfs4_mount(fs_volume* volume, const char* device, uint32 flags, { status_t result; - uint32 ip; + ServerAddress address; char path[256]; - result = ParseArguments(args, &ip, path); + result = ParseArguments(args, &address, path); if (result != B_OK) return result; - ServerAddress id; - id.fAddress = ip; - id.fPort = 2049; - id.fProtocol = IPPROTO_UDP; - RPC::Server *server; - result = gRPCServerManager->Acquire(&server, id, CreateNFS4Server); + result = gRPCServerManager->Acquire(&server, address, CreateNFS4Server); if (result != B_OK) return result; From 6fcc3500cff9f0a1eac2bcd52f7b42cc40583ef3 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Wed, 18 Jul 2012 18:27:19 +0200 Subject: [PATCH 139/252] nfs4: scokaddr_in::sa_len also needs to be filled --- src/add-ons/kernel/file_systems/nfs4/Connection.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Connection.cpp b/src/add-ons/kernel/file_systems/nfs4/Connection.cpp index 17e41cf6c5..af01bae305 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Connection.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Connection.cpp @@ -68,6 +68,7 @@ ServerAddress::ResolveName(const char* name, ServerAddress* address) struct sockaddr_in addr; memset(&addr, 0, sizeof(addr)); if (inet_aton(name, &addr.sin_addr) == 1) { + addr.sin_len = sizeof(addr); addr.sin_family = AF_INET; addr.sin_port = htons(NFS4_PORT); @@ -201,7 +202,6 @@ ConnectionPacket::Send(const void* buffer, uint32 size) status_t result = send(fSocket, buffer, size, 0); if (result < 0) return errno; - return B_OK; } @@ -394,7 +394,7 @@ Connection::Connect() } status_t result = connect(fSocket, &address, addressSize); - if (result < 0) { + if (result != 0) { result = errno; close(fSocket); return result; From 75fe7b90bbb751ea161dc6d4c81a3f8e694047b5 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Thu, 19 Jul 2012 01:49:24 +0200 Subject: [PATCH 140/252] nfs4: Add directory and name basic implementation --- .../file_systems/nfs4/CacheRevalidator.cpp | 113 +++++++++++++++ .../file_systems/nfs4/CacheRevalidator.h | 73 ++++++++++ .../file_systems/nfs4/DirectoryCache.cpp | 112 +++++++++++++++ .../kernel/file_systems/nfs4/DirectoryCache.h | 136 ++++++++++++++++++ .../kernel/file_systems/nfs4/FileSystem.h | 12 ++ .../kernel/file_systems/nfs4/Inode.cpp | 83 ++++++++++- src/add-ons/kernel/file_systems/nfs4/Inode.h | 4 + src/add-ons/kernel/file_systems/nfs4/Jamfile | 2 + .../file_systems/nfs4/ReplyInterpreter.cpp | 6 + 9 files changed, 537 insertions(+), 4 deletions(-) create mode 100644 src/add-ons/kernel/file_systems/nfs4/CacheRevalidator.cpp create mode 100644 src/add-ons/kernel/file_systems/nfs4/CacheRevalidator.h create mode 100644 src/add-ons/kernel/file_systems/nfs4/DirectoryCache.cpp create mode 100644 src/add-ons/kernel/file_systems/nfs4/DirectoryCache.h diff --git a/src/add-ons/kernel/file_systems/nfs4/CacheRevalidator.cpp b/src/add-ons/kernel/file_systems/nfs4/CacheRevalidator.cpp new file mode 100644 index 0000000000..6b13f04bd7 --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/CacheRevalidator.cpp @@ -0,0 +1,113 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ + + +#include "CacheRevalidator.h" + +#include + +#include "NFS4Defs.h" + + +CacheRevalidator::CacheRevalidator() + : + fThreadCancel(false), + fWaitCancel(create_sem(0, NULL)) +{ + mutex_init(&fDirectoryCachesLock, NULL); + + _StartRevalidator(); +} + + +CacheRevalidator::~CacheRevalidator() +{ + fThreadCancel = true; + release_sem(fWaitCancel); + status_t result; + wait_for_thread(fThread, &result); + + delete_sem(fThreadCancel); + mutex_destroy(&fDirectoryCachesLock); +} + + +status_t +CacheRevalidator::_StartRevalidator() +{ + fThreadCancel = false; + fThread = spawn_kernel_thread(&CacheRevalidator::_DirectoryRevalidatorStart, + "NFSv4 Cache Revalidator", B_NORMAL_PRIORITY, this); + if (fThread < B_OK) + return fThread; + + status_t result = resume_thread(fThread); + if (result != B_OK) { + kill_thread(fThread); + return result; + } + + return B_OK; +} + + +status_t +CacheRevalidator::_DirectoryRevalidatorStart(void* object) +{ + CacheRevalidator* revalidator = reinterpret_cast(object); + revalidator->_DirectoryCacheRevalidator(); + return B_OK; +} + + +void +CacheRevalidator::_DirectoryCacheRevalidator() +{ + while (!fThreadCancel) { + MutexLocker locker(fDirectoryCachesLock); + DirectoryCache* current = fDirectoryCaches.Head(); + + if (current == NULL) { + locker.Unlock(); + + status_t result = acquire_sem_etc(fWaitCancel, 1, + B_RELATIVE_TIMEOUT, DirectoryCache::kExpirationTime); + + if (result != B_TIMED_OUT) { + release_sem(fWaitCancel); + return; + } + continue; + } + + current->Lock(); + + if (current->ExpireTime() > system_time()) { + current->Unlock(); + locker.Unlock(); + + status_t result = acquire_sem_etc(fWaitCancel, 1, + B_ABSOLUTE_TIMEOUT, current->ExpireTime()); + if (result != B_TIMED_OUT) { + release_sem(fWaitCancel); + return; + } + + continue; + } + + fDirectoryCaches.RemoveHead(); + + if (current->Revalidate() == B_OK) + AddDirectory(current); + + locker.Unlock(); + current->Unlock(); + } +} + diff --git a/src/add-ons/kernel/file_systems/nfs4/CacheRevalidator.h b/src/add-ons/kernel/file_systems/nfs4/CacheRevalidator.h new file mode 100644 index 0000000000..86322d4e65 --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/CacheRevalidator.h @@ -0,0 +1,73 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ +#ifndef CACHEREVALIDATOR_H +#define CACHEREVALIDATOR_H + + +#include +#include +#include + +#include "DirectoryCache.h" + + +class CacheRevalidator { +public: + CacheRevalidator(); + ~CacheRevalidator(); + + inline void Lock(); + inline void Unlock(); + + + inline void AddDirectory(DirectoryCache* cache); + inline void RemoveDirectory(DirectoryCache* cache); + +private: + void _DirectoryCacheRevalidator(); + static status_t _DirectoryRevalidatorStart(void* object); + status_t _StartRevalidator(); + + thread_id fThread; + bool fThreadCancel; + sem_id fWaitCancel; + + DoublyLinkedQueue fDirectoryCaches; + mutex fDirectoryCachesLock; +}; + + +inline void +CacheRevalidator::Lock() +{ + mutex_lock(&fDirectoryCachesLock); +} + +inline void +CacheRevalidator::Unlock() +{ + mutex_unlock(&fDirectoryCachesLock); +} + + +inline void +CacheRevalidator::AddDirectory(DirectoryCache* cache) +{ + fDirectoryCaches.Add(cache); +} + + +inline void +CacheRevalidator::RemoveDirectory(DirectoryCache* cache) +{ + fDirectoryCaches.Remove(cache); +} + + +#endif // CACHEREVALIDATOR_H + diff --git a/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.cpp b/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.cpp new file mode 100644 index 0000000000..73dd3b5f21 --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.cpp @@ -0,0 +1,112 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ + + +#include "DirectoryCache.h" + +#include + +#include "Inode.h" + + +DirectoryCache::DirectoryCache(Inode* inode) + : + fInode(inode), + fTrashed(true) +{ + mutex_init(&fLock, NULL); +} + + +DirectoryCache::~DirectoryCache() +{ + mutex_destroy(&fLock); +} + + +void +DirectoryCache::ResetAndLock() +{ + mutex_lock(&fLock); + Trash(); + fExpireTime = system_time() + kExpirationTime; + fTrashed = false; +} + + +void +DirectoryCache::Trash() +{ + while (!fNameCache.IsEmpty()) { + NameCacheEntry* current = fNameCache.RemoveHead(); + entry_cache_remove(fInode->GetFileSystem()->DevId(), fInode->ID(), + current->fName); + free(const_cast(current->fName)); + delete current; + } + + fTrashed = true; +} + + +status_t +DirectoryCache::AddEntry(const char* name, ino_t node) +{ + NameCacheEntry* entry = new(std::nothrow) NameCacheEntry; + if (entry == NULL) + return B_NO_MEMORY; + + entry->fName = strdup(name); + if (entry->fName == NULL) { + delete entry; + return B_NO_MEMORY; + } + entry->fNode = node; + fNameCache.Add(entry); + + return entry_cache_add(fInode->GetFileSystem()->DevId(), fInode->ID(), name, + node); +} + +void +DirectoryCache::RemoveEntry(const char* name) +{ + SinglyLinkedList::Iterator iterator + = fNameCache.GetIterator(); + NameCacheEntry* previous = NULL; + NameCacheEntry* current = iterator.Next(); + while (current != NULL) { + if (strcmp(current->fName, name) == 0) { + free(const_cast(current->fName)); + delete current; + + fNameCache.Remove(previous, current); + break; + } + + previous = current; + current = iterator.Next(); + } + + entry_cache_remove(fInode->GetFileSystem()->DevId(), fInode->ID(), name); +} + + +status_t +DirectoryCache::Revalidate() +{ + uint64 change; + if (fInode->GetChangeInfo(&change) == B_OK && change == fChange) { + fExpireTime = system_time() + kExpirationTime; + return B_OK; + } + + Trash(); + return B_ERROR; +} + diff --git a/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.h b/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.h new file mode 100644 index 0000000000..f5e949fe9e --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.h @@ -0,0 +1,136 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ +#ifndef DIRECTORYCACHE_H +#define DIRECTORYCACHE_H + + +#include +#include +#include +#include + + +class Inode; + +struct NameCacheEntry : + public SinglyLinkedListLinkImpl { + ino_t fNode; + const char* fName; +}; + + +class DirectoryCache : public DoublyLinkedListLinkImpl { +public: + DirectoryCache(Inode* inode); + ~DirectoryCache(); + + inline status_t Lock(); + inline void Unlock(); + + void ResetAndLock(); + void Trash(); + + status_t AddEntry(const char* name, ino_t node); + void RemoveEntry(const char* name); + + inline SinglyLinkedList& EntriesList(); + + status_t Revalidate(); + + inline status_t ValidateChangeInfo(uint64 change); + inline void SetChangeInfo(uint64 change); + inline uint64 ChangeInfo(); + + inline Inode* GetInode(); + inline time_t ExpireTime(); + + static const bigtime_t kExpirationTime = 5000000; +private: + SinglyLinkedList fNameCache; + + Inode* fInode; + + bool fTrashed; + mutex fLock; + + uint64 fChange; + bigtime_t fExpireTime; +}; + + +inline status_t +DirectoryCache::Lock() +{ + mutex_lock(&fLock); + if (fTrashed) { + mutex_unlock(&fLock); + return B_ERROR; + } + + return B_OK; +} + +inline void +DirectoryCache::Unlock() +{ + mutex_unlock(&fLock); +} + + +inline SinglyLinkedList& +DirectoryCache::EntriesList() +{ + return fNameCache; +} + + +inline status_t +DirectoryCache::ValidateChangeInfo(uint64 change) +{ + if (fTrashed || change != fChange) { + Trash(); + change = fChange; + fExpireTime = system_time() + kExpirationTime; + return B_ERROR; + } + + return B_OK; +} + + +inline void +DirectoryCache::SetChangeInfo(uint64 change) +{ + fExpireTime = system_time() + kExpirationTime; + fChange = change; +} + + +inline uint64 +DirectoryCache::ChangeInfo() +{ + return fChange; +} + + +inline Inode* +DirectoryCache::GetInode() +{ + return fInode; +} + + +inline time_t +DirectoryCache::ExpireTime() +{ + return fExpireTime; +} + + +#endif // DIRECTORYCACHE_H + diff --git a/src/add-ons/kernel/file_systems/nfs4/FileSystem.h b/src/add-ons/kernel/file_systems/nfs4/FileSystem.h index 3a30659329..7b99ef720a 100644 --- a/src/add-ons/kernel/file_systems/nfs4/FileSystem.h +++ b/src/add-ons/kernel/file_systems/nfs4/FileSystem.h @@ -9,6 +9,7 @@ #define FILESYSTEM_H +#include "CacheRevalidator.h" #include "InodeIdMap.h" #include "NFS4Defs.h" #include "NFS4Server.h" @@ -34,6 +35,8 @@ public: void AddOpenFile(OpenFileCookie* cookie); void RemoveOpenFile(OpenFileCookie* cookie); + inline CacheRevalidator& Revalidator(); + inline bool IsAttrSupported(Attribute attr) const; inline uint32 ExpireType() const; @@ -53,6 +56,8 @@ public: private: FileSystem(); + CacheRevalidator fCacheRevalidator; + OpenFileCookie* fOpenFiles; uint32 fOpenCount; mutex fOpenLock; @@ -74,6 +79,13 @@ private: }; +inline CacheRevalidator& +FileSystem::Revalidator() +{ + return fCacheRevalidator; +} + + inline RootInode* FileSystem::Root() { diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index 1614cb754f..f5ba22c80f 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -21,7 +21,8 @@ Inode::Inode() : - fAttrCacheExpire(0) + fAttrCacheExpire(0), + fCache(NULL) { mutex_init(&fAttrCacheLock, NULL); } @@ -80,6 +81,9 @@ Inode::CreateInode(FileSystem* fs, const FileInfo &fi, Inode** _inode) // FATTR4_TYPE is mandatory inode->fType = values[0].fData.fValue32; + if (inode->fType == NF4DIR) + inode->fCache = new DirectoryCache(inode); + // FATTR4_FSID is mandatory FileSystemId* fsid = reinterpret_cast(values[1].fData.fPointer); @@ -99,10 +103,50 @@ Inode::CreateInode(FileSystem* fs, const FileInfo &fi, Inode** _inode) Inode::~Inode() { + delete fCache; mutex_destroy(&fAttrCacheLock); } +status_t +Inode::GetChangeInfo(uint64* change) +{ + do { + RPC::Server* serv = fFileSystem->Server(); + Request request(serv); + RequestBuilder& req = request.Builder(); + + req.PutFH(fInfo.fHandle); + + Attribute attr[] = { FATTR4_CHANGE }; + req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); + + status_t result = request.Send(); + if (result != B_OK) + return result; + + ReplyInterpreter& reply = request.Reply(); + + if (_HandleErrors(reply.NFS4Error(), serv)) + continue; + + reply.PutFH(); + + AttrValue* values; + uint32 count; + result = reply.GetAttr(&values, &count); + if (result != B_OK || count < 1) + return result; + + // FATTR4_CHANGE is mandatory + *change = values[0].fData.fValue64; + delete[] values; + + return B_OK; + } while (true); +} + + status_t Inode::LookUp(const char* name, ino_t* id) { @@ -121,6 +165,9 @@ Inode::LookUp(const char* name, ino_t* id) req.PutFH(fInfo.fHandle); + Attribute dirAttr[] = { FATTR4_CHANGE }; + req.GetAttr(dirAttr, sizeof(dirAttr) / sizeof(Attribute)); + if (!strcmp(name, "..")) req.LookUpUp(); else @@ -141,6 +188,16 @@ Inode::LookUp(const char* name, ino_t* id) continue; reply.PutFH(); + + AttrValue* values; + uint32 count; + result = reply.GetAttr(&values, &count); + if (result != B_OK) + return result; + + uint64 change = values[0].fData.fValue64; + delete[] values; + if (!strcmp(name, "..")) result = reply.LookUpUp(); else @@ -151,8 +208,6 @@ Inode::LookUp(const char* name, ino_t* id) FileHandle fh; reply.GetFH(&fh); - AttrValue* values; - uint32 count; result = reply.GetAttr(&values, &count); if (result != B_OK) return result; @@ -194,6 +249,20 @@ Inode::LookUp(const char* name, ino_t* id) fFileSystem->InoIdMap()->AddEntry(fi, *id); + fFileSystem->Revalidator().Lock(); + if (fCache->Lock() != B_OK) { + fCache->ResetAndLock(); + fCache->SetChangeInfo(change); + } else { + fFileSystem->Revalidator().RemoveDirectory(fCache); + fCache->ValidateChangeInfo(change); + } + + fCache->AddEntry(name, *id); + fFileSystem->Revalidator().AddDirectory(fCache); + fCache->Unlock(); + fFileSystem->Revalidator().Unlock(); + return B_OK; } while (true); } @@ -294,6 +363,8 @@ Inode::Remove(const char* name, FileType type) reply.PutFH(); result = reply.Remove(); + // remove entry + fFileSystem->Root()->MakeInfoInvalid(); return result; @@ -344,7 +415,11 @@ Inode::Rename(Inode* from, Inode* to, const char* fromName, const char* toName) reply.SaveFH(); reply.PutFH(); - return reply.Rename(); + result = reply.Rename(); + + // remove entry + + return result; } while (true); } diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h b/src/add-ons/kernel/file_systems/nfs4/Inode.h index 9ca2466879..76f589d334 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -30,6 +30,8 @@ public: inline const char* Name() const; inline FileSystem* GetFileSystem() const; + status_t GetChangeInfo(uint64* change); + status_t LookUp(const char* name, ino_t* id); status_t CreateLink(const char* name, const char* path, @@ -99,6 +101,8 @@ protected: FileInfo fInfo; FileSystem* fFileSystem; + + DirectoryCache* fCache; }; diff --git a/src/add-ons/kernel/file_systems/nfs4/Jamfile b/src/add-ons/kernel/file_systems/nfs4/Jamfile index 5350ac5a9b..0d77bb21f5 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Jamfile +++ b/src/add-ons/kernel/file_systems/nfs4/Jamfile @@ -4,8 +4,10 @@ UsePrivateKernelHeaders ; UsePrivateHeaders shared ; KernelAddon nfs4 : + CacheRevalidator.cpp Cookie.cpp Connection.cpp + DirectoryCache.cpp FileInfo.cpp FileSystem.cpp IdMap.cpp diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp index 8306a586e7..a142bac08a 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp @@ -528,6 +528,12 @@ ReplyInterpreter::_DecodeAttrs(XDR::ReadStream& str, AttrValue** attrs, current++; } + if (sIsAttrSet(FATTR4_CHANGE, bitmap, bcount)) { + values[current].fAttribute = FATTR4_CHANGE; + values[current].fData.fValue64 = stream.GetUHyper(); + current++; + } + if (sIsAttrSet(FATTR4_SIZE, bitmap, bcount)) { values[current].fAttribute = FATTR4_SIZE; values[current].fData.fValue64 = stream.GetUHyper(); From 7b6f80fee2eee9724b8146cc480c0ffe87b25c32 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Thu, 19 Jul 2012 02:25:04 +0200 Subject: [PATCH 141/252] nfs4: Do not let local changes invalidate cache --- .../kernel/file_systems/nfs4/Inode.cpp | 70 +++++++++++++++++-- .../kernel/file_systems/nfs4/InodeDir.cpp | 18 ++++- .../file_systems/nfs4/ReplyInterpreter.cpp | 40 +++++------ .../file_systems/nfs4/ReplyInterpreter.h | 10 +-- 4 files changed, 107 insertions(+), 31 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index f5ba22c80f..f49a0c2f25 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -304,7 +304,23 @@ Inode::Link(Inode* dir, const char* name) reply.SaveFH(); reply.PutFH(); - return reply.Link(); + uint64 before, after; + bool atomic; + result = reply.Link(&before, &after, atomic); + if (result != B_OK) + return result; + + if (fCache->Lock() == B_OK) { + if (atomic && fCache->ChangeInfo() == before) { + // TODO: update cache + //fCache->AddEntry(name, ); + fCache->SetChangeInfo(after); + } else if (fCache->ChangeInfo() != before) + fCache->Trash(); + fCache->Unlock(); + } + + return B_OK; } while (true); } @@ -361,9 +377,19 @@ Inode::Remove(const char* name, FileType type) return result; reply.PutFH(); - result = reply.Remove(); - // remove entry + uint64 before, after; + bool atomic; + result = reply.Remove(&before, &after, atomic); + + if (fCache->Lock() == B_OK) { + if (atomic && fCache->ChangeInfo() == before) { + fCache->RemoveEntry(name); + fCache->SetChangeInfo(after); + } else if (fCache->ChangeInfo() != before) + fCache->Trash(); + fCache->Unlock(); + } fFileSystem->Root()->MakeInfoInvalid(); @@ -415,9 +441,29 @@ Inode::Rename(Inode* from, Inode* to, const char* fromName, const char* toName) reply.SaveFH(); reply.PutFH(); - result = reply.Rename(); + uint64 fromBefore, fromAfter, toBefore, toAfter; + bool fromAtomic, toAtomic; + result = reply.Rename(&fromBefore, &fromAfter, fromAtomic, &toBefore, + &toAfter, toAtomic); - // remove entry + if (from->fCache->Lock() == B_OK) { + if (fromAtomic && from->fCache->ChangeInfo() == fromBefore) { + from->fCache->RemoveEntry(fromName); + from->fCache->SetChangeInfo(fromAfter); + } else if (from->fCache->ChangeInfo() != fromBefore) + from->fCache->Trash(); + from->fCache->Unlock(); + } + + if (to->fCache->Lock() == B_OK) { + if (toAtomic && to->fCache->ChangeInfo() == toBefore) { + // TODO: update cache + //fCache->AddEntry(toName, ); + to->fCache->SetChangeInfo(toAfter); + } else if (to->fCache->ChangeInfo() != toBefore) + to->fCache->Trash(); + to->fCache->Unlock(); + }; return result; } while (true); @@ -474,10 +520,22 @@ Inode::CreateLink(const char* name, const char* path, int mode) reply.PutFH(); - result = reply.Create(); + uint64 before, after; + bool atomic; + result = reply.Create(&before, &after, atomic); fFileSystem->Root()->MakeInfoInvalid(); + if (fCache->Lock() == B_OK) { + if (atomic && fCache->ChangeInfo() == before) { + // TODO: update cache + //fCache->AddEntry(name, ); + fCache->SetChangeInfo(after); + } else if (fCache->ChangeInfo() != before) + fCache->Trash(); + fCache->Unlock(); + } + return result; } while (true); } diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp b/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp index 47d6f8766b..4671f97a31 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp @@ -67,7 +67,23 @@ Inode::CreateDir(const char* name, int mode) reply.PutFH(); - return reply.Create(); + uint64 before, after; + bool atomic; + result = reply.Create(&before, &after, atomic); + + fFileSystem->Root()->MakeInfoInvalid(); + + if (fCache->Lock() == B_OK) { + if (atomic && fCache->ChangeInfo() == before) { + // TODO: update cache + //fCache->AddEntry(name, ); + fCache->SetChangeInfo(after); + } else if (fCache->ChangeInfo() != before) + fCache->Trash(); + fCache->Unlock(); + } + + return result; } while (true); } diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp index a142bac08a..eedc5afeee 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp @@ -126,15 +126,15 @@ ReplyInterpreter::Close() status_t -ReplyInterpreter::Create() +ReplyInterpreter::Create(uint64* before, uint64* after, bool& atomic) { status_t res = _OperationError(OpCreate); if (res != B_OK) return res; - fReply->Stream().GetBoolean(); - fReply->Stream().GetUHyper(); - fReply->Stream().GetUHyper(); + atomic = fReply->Stream().GetBoolean(); + *before = fReply->Stream().GetUHyper(); + *after = fReply->Stream().GetUHyper(); uint32 count = fReply->Stream().GetUInt(); for (uint32 i; i < count; i++) fReply->Stream().GetUInt(); @@ -187,15 +187,15 @@ ReplyInterpreter::GetFH(FileHandle* fh) status_t -ReplyInterpreter::Link() +ReplyInterpreter::Link(uint64* before, uint64* after, bool& atomic) { status_t res = _OperationError(OpLink); if (res != B_OK) return res; - fReply->Stream().GetBoolean(); - fReply->Stream().GetUHyper(); - fReply->Stream().GetUHyper(); + atomic = fReply->Stream().GetBoolean(); + *before = fReply->Stream().GetUHyper(); + *after = fReply->Stream().GetUHyper(); return fReply->Stream().IsEOF() ? B_BAD_VALUE : B_OK; } @@ -369,35 +369,35 @@ ReplyInterpreter::ReadLink(void* buffer, uint32* size, uint32 maxSize) status_t -ReplyInterpreter::Remove() +ReplyInterpreter::Remove(uint64* before, uint64* after, bool& atomic) { status_t res = _OperationError(OpRemove); if (res != B_OK) return res; - fReply->Stream().GetBoolean(); - fReply->Stream().GetUHyper(); - fReply->Stream().GetUHyper(); + atomic = fReply->Stream().GetBoolean(); + *before = fReply->Stream().GetUHyper(); + *after = fReply->Stream().GetUHyper(); return fReply->Stream().IsEOF() ? B_BAD_VALUE : B_OK; } status_t -ReplyInterpreter::Rename() +ReplyInterpreter::Rename(uint64* fromBefore, uint64* fromAfter, + bool& fromAtomic, uint64* toBefore, uint64* toAfter, bool& toAtomic) { status_t res = _OperationError(OpRename); if (res != B_OK) return res; - fReply->Stream().GetBoolean(); - fReply->Stream().GetUHyper(); - fReply->Stream().GetUHyper(); - - fReply->Stream().GetBoolean(); - fReply->Stream().GetUHyper(); - fReply->Stream().GetUHyper(); + fromAtomic = fReply->Stream().GetBoolean(); + *fromBefore = fReply->Stream().GetUHyper(); + *fromAfter = fReply->Stream().GetUHyper(); + toAtomic = fReply->Stream().GetBoolean(); + *toBefore = fReply->Stream().GetUHyper(); + *toAfter = fReply->Stream().GetUHyper(); return fReply->Stream().IsEOF() ? B_BAD_VALUE : B_OK; } diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h index eedd9ea645..92739d2f95 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h @@ -69,10 +69,10 @@ public: status_t Access(uint32* supported, uint32* allowed); status_t Close(); - status_t Create(); + status_t Create(uint64* before, uint64* after, bool& atomic); status_t GetAttr(AttrValue** attrs, uint32* count); status_t GetFH(FileHandle* fh); - status_t Link(); + status_t Link(uint64* before, uint64* after, bool& atomic); status_t Lock(LockInfo* linfo); status_t LockT(uint64* pos, uint64* len, LockType* type); status_t LockU(LockInfo* linfo); @@ -87,8 +87,10 @@ public: status_t ReadDir(uint64* cookie, uint64* cookieVerf, DirEntry** dirents, uint32* count, bool* eof); status_t ReadLink(void* buffer, uint32* size, uint32 maxSize); - status_t Remove(); - status_t Rename(); + status_t Remove(uint64* before, uint64* after, bool& atomic); + status_t Rename(uint64* fromBefore, uint64* fromAfter, + bool& fromAtomic, uint64* toBefore, uint64* toAfter, + bool& toAtomic); inline status_t Renew(); inline status_t SaveFH(); status_t SetAttr(); From 09dbdd3644142673a8df63ae77ff8ccd4524c835 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Fri, 20 Jul 2012 03:41:21 +0200 Subject: [PATCH 142/252] nfs4: Add full directory cache implementation --- .../file_systems/nfs4/CacheRevalidator.cpp | 3 +- .../kernel/file_systems/nfs4/Cookie.cpp | 7 + src/add-ons/kernel/file_systems/nfs4/Cookie.h | 7 +- .../file_systems/nfs4/DirectoryCache.cpp | 74 +++++- .../kernel/file_systems/nfs4/DirectoryCache.h | 30 ++- src/add-ons/kernel/file_systems/nfs4/Inode.h | 7 +- .../kernel/file_systems/nfs4/InodeDir.cpp | 224 +++++++++++++----- .../file_systems/nfs4/ReplyInterpreter.cpp | 25 +- src/add-ons/kernel/file_systems/nfs4/XDR.h | 9 + 9 files changed, 312 insertions(+), 74 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/CacheRevalidator.cpp b/src/add-ons/kernel/file_systems/nfs4/CacheRevalidator.cpp index 6b13f04bd7..6c5e05dadc 100644 --- a/src/add-ons/kernel/file_systems/nfs4/CacheRevalidator.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/CacheRevalidator.cpp @@ -85,7 +85,8 @@ CacheRevalidator::_DirectoryCacheRevalidator() continue; } - current->Lock(); + if (current->Lock() != B_OK) + continue; if (current->ExpireTime() > system_time()) { current->Unlock(); diff --git a/src/add-ons/kernel/file_systems/nfs4/Cookie.cpp b/src/add-ons/kernel/file_systems/nfs4/Cookie.cpp index 0102d68b86..016d107a20 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Cookie.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Cookie.cpp @@ -233,3 +233,10 @@ OpenFileCookie::_ReleaseLockOwner(LockOwner* owner) return reply.ReleaseLockOwner(); } + +OpenDirCookie::~OpenDirCookie() +{ + if (fSnapshot != NULL) + fSnapshot->ReleaseReference(); +} + diff --git a/src/add-ons/kernel/file_systems/nfs4/Cookie.h b/src/add-ons/kernel/file_systems/nfs4/Cookie.h index 364dc17c5d..38a77d3ad4 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Cookie.h +++ b/src/add-ons/kernel/file_systems/nfs4/Cookie.h @@ -106,8 +106,11 @@ private: }; struct OpenDirCookie : public Cookie { - uint64 fCookie; - uint64 fCookieVerf; + DirectoryCacheSnapshot* fSnapshot; + NameCacheEntry* fCurrent; + bool fEOF; + + ~OpenDirCookie(); }; diff --git a/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.cpp b/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.cpp index 73dd3b5f21..a3065aa286 100644 --- a/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.cpp @@ -14,8 +14,41 @@ #include "Inode.h" + +NameCacheEntry::NameCacheEntry(const char* name, ino_t node) + : + fNode(node), + fName(strdup(name)) +{ +} + + +NameCacheEntry::~NameCacheEntry() +{ + free(const_cast(fName)); +} + + +DirectoryCacheSnapshot::DirectoryCacheSnapshot() +{ + mutex_init(&fLock, NULL); +} + + +DirectoryCacheSnapshot::~DirectoryCacheSnapshot() +{ + while (!fEntries.IsEmpty()) { + NameCacheEntry* current = fEntries.RemoveHead(); + delete current; + } + + mutex_destroy(&fLock); +} + + DirectoryCache::DirectoryCache(Inode* inode) : + fDirectoryCache(NULL), fInode(inode), fTrashed(true) { @@ -46,27 +79,26 @@ DirectoryCache::Trash() NameCacheEntry* current = fNameCache.RemoveHead(); entry_cache_remove(fInode->GetFileSystem()->DevId(), fInode->ID(), current->fName); - free(const_cast(current->fName)); delete current; } + SetSnapshot(NULL); + fTrashed = true; } - +// TODO: separate AddEntry() for Name and Directory Cache are needed status_t DirectoryCache::AddEntry(const char* name, ino_t node) { - NameCacheEntry* entry = new(std::nothrow) NameCacheEntry; + NameCacheEntry* entry = new(std::nothrow) NameCacheEntry(name, node); if (entry == NULL) return B_NO_MEMORY; - - entry->fName = strdup(name); if (entry->fName == NULL) { delete entry; return B_NO_MEMORY; } - entry->fNode = node; + fNameCache.Add(entry); return entry_cache_add(fInode->GetFileSystem()->DevId(), fInode->ID(), name, @@ -82,10 +114,8 @@ DirectoryCache::RemoveEntry(const char* name) NameCacheEntry* current = iterator.Next(); while (current != NULL) { if (strcmp(current->fName, name) == 0) { - free(const_cast(current->fName)); - delete current; - fNameCache.Remove(previous, current); + delete current; break; } @@ -93,10 +123,36 @@ DirectoryCache::RemoveEntry(const char* name) current = iterator.Next(); } + if (fDirectoryCache != NULL) { + MutexLocker _(fDirectoryCache->fLock); + iterator = fDirectoryCache->fEntries.GetIterator(); + previous = NULL; + current = iterator.Next(); + while (current != NULL) { + if (strcmp(current->fName, name) == 0) { + fDirectoryCache->fEntries.Remove(previous, current); + delete current; + break; + } + + previous = current; + current = iterator.Next(); + } + } + entry_cache_remove(fInode->GetFileSystem()->DevId(), fInode->ID(), name); } +void +DirectoryCache::SetSnapshot(DirectoryCacheSnapshot* snapshot) +{ + if (fDirectoryCache != NULL) + fDirectoryCache->ReleaseReference(); + fDirectoryCache = snapshot; +} + + status_t DirectoryCache::Revalidate() { diff --git a/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.h b/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.h index f5e949fe9e..0e9b07ba13 100644 --- a/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.h +++ b/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.h @@ -12,6 +12,7 @@ #include #include #include +#include #include @@ -21,8 +22,18 @@ struct NameCacheEntry : public SinglyLinkedListLinkImpl { ino_t fNode; const char* fName; + + NameCacheEntry(const char* name, ino_t node); + ~NameCacheEntry(); }; +struct DirectoryCacheSnapshot : public KernelReferenceable { + SinglyLinkedList fEntries; + mutex fLock; + + DirectoryCacheSnapshot(); + ~DirectoryCacheSnapshot(); +}; class DirectoryCache : public DoublyLinkedListLinkImpl { public: @@ -38,6 +49,9 @@ public: status_t AddEntry(const char* name, ino_t node); void RemoveEntry(const char* name); + void SetSnapshot(DirectoryCacheSnapshot* snapshot); + inline DirectoryCacheSnapshot* GetSnapshot(); + inline SinglyLinkedList& EntriesList(); status_t Revalidate(); @@ -53,6 +67,9 @@ public: private: SinglyLinkedList fNameCache; + DirectoryCacheSnapshot* fDirectoryCache; + //mutex fDirectoryCacheLock; + Inode* fInode; bool fTrashed; @@ -82,7 +99,14 @@ DirectoryCache::Unlock() } -inline SinglyLinkedList& +inline DirectoryCacheSnapshot* +DirectoryCache::GetSnapshot() +{ + return fDirectoryCache; +} + + +inline SinglyLinkedList& DirectoryCache::EntriesList() { return fNameCache; @@ -94,8 +118,10 @@ DirectoryCache::ValidateChangeInfo(uint64 change) { if (fTrashed || change != fChange) { Trash(); - change = fChange; + fChange = change; fExpireTime = system_time() + kExpirationTime; + fTrashed = false; + return B_ERROR; } diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h b/src/add-ons/kernel/file_systems/nfs4/Inode.h index 76f589d334..feb9964c94 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -81,11 +81,16 @@ protected: OpenFileCookie* cookie); status_t _ReadDirOnce(DirEntry** dirents, uint32* count, - OpenDirCookie* cookie, bool* eof); + 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); + status_t _GetDirSnapshot(DirectoryCacheSnapshot** + _snapshot, OpenDirCookie* cookie, + uint64* _change); static inline status_t _CheckLockType(short ltype, uint32 mode); diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp b/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp index 4671f97a31..05af489268 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp @@ -122,8 +122,9 @@ Inode::OpenDir(OpenDirCookie* cookie) return B_PERMISSION_DENIED; cookie->fFileSystem = fFileSystem; - cookie->fCookie = 0; - cookie->fCookieVerf = 2; + cookie->fSnapshot = NULL; + cookie->fCurrent = NULL; + cookie->fEOF = false; fFileSystem->Root()->MakeInfoInvalid(); @@ -134,7 +135,7 @@ Inode::OpenDir(OpenDirCookie* cookie) status_t Inode::_ReadDirOnce(DirEntry** dirents, uint32* count, OpenDirCookie* cookie, - bool* eof) + bool* eof, uint64* change, uint64* dirCookie, uint64* dirCookieVerf) { do { RPC::Server* serv = fFileSystem->Server(); @@ -143,10 +144,16 @@ Inode::_ReadDirOnce(DirEntry** dirents, uint32* count, OpenDirCookie* cookie, 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, cookie->fCookie, cookie->fCookieVerf, attr, + 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; @@ -157,8 +164,39 @@ Inode::_ReadDirOnce(DirEntry** dirents, uint32* count, OpenDirCookie* cookie, continue; reply.PutFH(); - return reply.ReadDir(&cookie->fCookie, &cookie->fCookieVerf, dirents, + + 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); } @@ -236,23 +274,67 @@ Inode::_ReadDirUp(struct dirent* de, uint32 pos, uint32 size) } while (true); } -// TODO: Currently inode numbers returned by ReadDir are virtually random. -// Apparently Haiku does not use that information (contrary to inode number -// returned by LookUp) so fixing it can wait until directory caches are -// implemented. -// When directories are cached client should store inode numbers it assigned -// to directroy entries and use them consequently. + status_t -Inode::ReadDir(void* _buffer, uint32 size, uint32* _count, - OpenDirCookie* cookie) +Inode::_GetDirSnapshot(DirectoryCacheSnapshot** _snapshot, + OpenDirCookie* cookie, uint64* _change) { - uint32 count = 0; - uint32 pos = 0; - uint32 this_count; + DirectoryCacheSnapshot* snapshot = new DirectoryCacheSnapshot; + if (snapshot == NULL) + return B_NO_MEMORY; + + uint64 change = 0; + uint64 dirCookie = 0; + uint64 dirCookieVerf = 0; bool eof = false; - char* buffer = reinterpret_cast(_buffer); + while (!eof) { + uint32 count; + DirEntry* dirents; + status_t result = _ReadDirOnce(&dirents, &count, cookie, &eof, &change, + &dirCookie, &dirCookieVerf); + if (result != B_OK) { + delete snapshot; + return result; + } + + uint32 i; + for (i = 0; i < count; i++) { + + // FATTR4_FSID is mandatory + void* data = dirents[i].fAttrs[0].fData.fPointer; + FileSystemId* fsid = reinterpret_cast(data); + if (*fsid != fFileSystem->FsId()) + continue; + + ino_t id; + if (dirents[i].fAttrCount == 2) + id = _FileIdToInoT(dirents[i].fAttrs[1].fData.fValue64); + else + id = _FileIdToInoT(fFileSystem->AllocFileId()); + + NameCacheEntry* entry = new NameCacheEntry(dirents[i].fName, id); + if (entry == NULL || entry->fName == NULL) { + if (entry->fName == NULL) + delete entry; + delete snapshot; + delete[] dirents; + return B_NO_MEMORY; + } + snapshot->fEntries.Add(entry); + } + + delete[] dirents; + } + + *_snapshot = snapshot; + *_change = change; + + return B_OK; +} + +/* if (cookie->fCookie == 0 && cookie->fCookieVerf == 2 && count < *_count) { struct dirent* de = reinterpret_cast(buffer + pos); @@ -275,51 +357,79 @@ Inode::ReadDir(void* _buffer, uint32 size, uint32* _count, count++; cookie->fCookieVerf--; } +*/ - bool overflow = false; - while (count < *_count && !eof) { - this_count = *_count - count; - DirEntry* dirents; - - status_t result = _ReadDirOnce(&dirents, &this_count, cookie, &eof); - if (result != B_OK) - return result; - - uint32 i, entries = 0; - for (i = 0; i < min_c(this_count, *_count - count); i++) { - struct dirent* de = reinterpret_cast(buffer + pos); - - // FATTR4_FSID is mandatory - void* data = dirents[i].fAttrs[0].fData.fPointer; - FileSystemId* fsid = reinterpret_cast(data); - if (*fsid != fFileSystem->FsId()) - continue; - - ino_t id; - if (dirents[i].fAttrCount == 2) - id = _FileIdToInoT(dirents[i].fAttrs[1].fData.fValue64); - else - id = _FileIdToInoT(fFileSystem->AllocFileId()); - - const char* name = dirents[i].fName; - if (_FillDirEntry(de, id, name, pos, size) == B_BUFFER_OVERFLOW) { - eof = true; - overflow = true; - break; - } - - pos += de->d_reclen; - entries++; - } - delete[] dirents; - count += entries; +status_t +Inode::ReadDir(void* _buffer, uint32 size, uint32* _count, + OpenDirCookie* cookie) +{ + if (cookie->fEOF) { + *_count = 0; + return B_OK; } - if (count == 0 && overflow) + status_t result; + if (cookie->fSnapshot == NULL) { + fFileSystem->Revalidator().Lock(); + if (fCache->Lock() != B_OK) { + fCache->ResetAndLock(); + } else { + fFileSystem->Revalidator().RemoveDirectory(fCache); + } + + cookie->fSnapshot = fCache->GetSnapshot(); + if (cookie->fSnapshot == NULL) { + uint64 change; + result = _GetDirSnapshot(&cookie->fSnapshot, cookie, &change); + if (result != B_OK) { + fCache->Unlock(); + fFileSystem->Revalidator().Unlock(); + return result; + } + fCache->ValidateChangeInfo(change); + fCache->SetSnapshot(cookie->fSnapshot); + } + cookie->fSnapshot->AcquireReference(); + fFileSystem->Revalidator().AddDirectory(fCache); + fCache->Unlock(); + fFileSystem->Revalidator().Unlock(); + } + + char* buffer = reinterpret_cast(_buffer); + uint32 pos = 0; + + MutexLocker _(cookie->fSnapshot->fLock); + uint32 i; + bool overflow = false; + for (i = 0; i < *_count; i++) { + struct dirent* de = reinterpret_cast(buffer + pos); + + if (cookie->fCurrent == NULL) + cookie->fCurrent = cookie->fSnapshot->fEntries.Head(); + else { + cookie->fCurrent + = cookie->fSnapshot->fEntries.GetNext(cookie->fCurrent); + } + + if (cookie->fCurrent == NULL) { + cookie->fEOF = true; + break; + } + + if (_FillDirEntry(de, cookie->fCurrent->fNode, cookie->fCurrent->fName, + pos, size) == B_BUFFER_OVERFLOW) { + overflow = true; + break; + } + + pos += de->d_reclen; + } + + if (i == 0 && overflow) return B_BUFFER_OVERFLOW; - *_count = count; - + *_count = i; + return B_OK; } diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp index eedc5afeee..c80b5da395 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp @@ -326,12 +326,33 @@ ReplyInterpreter::ReadDir(uint64* cookie, uint64* cookieVerf, bool isNext; uint32 count = 0; - DirEntry* entries = new(std::nothrow) DirEntry[*_count]; + + // TODO: using list instead of array would make this much more elegant + // and efficient + XDR::Stream::Position dataStart = fReply->Stream().Current(); + isNext = fReply->Stream().GetBoolean(); + while (isNext) { + fReply->Stream().GetUHyper(); + + free(fReply->Stream().GetString()); + AttrValue* values; + uint32 attrCount; + _DecodeAttrs(fReply->Stream(), &values, &attrCount); + delete[] values; + + count++; + + isNext = fReply->Stream().GetBoolean(); + } + + DirEntry* entries = new(std::nothrow) DirEntry[count]; if (entries == NULL) return B_NO_MEMORY; + count = 0; + fReply->Stream().SetPosition(dataStart); isNext = fReply->Stream().GetBoolean(); - while (isNext && count < *_count) { + while (isNext) { *cookie = fReply->Stream().GetUHyper(); entries[count].fName = fReply->Stream().GetString(); diff --git a/src/add-ons/kernel/file_systems/nfs4/XDR.h b/src/add-ons/kernel/file_systems/nfs4/XDR.h index f52ae0f9e9..78cfbc6392 100644 --- a/src/add-ons/kernel/file_systems/nfs4/XDR.h +++ b/src/add-ons/kernel/file_systems/nfs4/XDR.h @@ -39,6 +39,8 @@ public: ReadStream(void* buffer, uint32 size); virtual ~ReadStream(); + inline void SetPosition(Position position); + inline int Size() const; int32 GetInt(); @@ -108,6 +110,13 @@ Stream::Current() const } +inline void +ReadStream::SetPosition(Position position) +{ + fPosition = position; +} + + inline int ReadStream::Size() const { From 6b9a91eb660bb88915f900678e3f3609b71135d1 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Fri, 20 Jul 2012 03:56:12 +0200 Subject: [PATCH 143/252] nfs4: ReadDir sholud not including '..' and '.' --- src/add-ons/kernel/file_systems/nfs4/Cookie.h | 1 + .../kernel/file_systems/nfs4/InodeDir.cpp | 66 +++++++++++-------- 2 files changed, 40 insertions(+), 27 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Cookie.h b/src/add-ons/kernel/file_systems/nfs4/Cookie.h index 38a77d3ad4..c5b0528ce4 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Cookie.h +++ b/src/add-ons/kernel/file_systems/nfs4/Cookie.h @@ -106,6 +106,7 @@ private: }; struct OpenDirCookie : public Cookie { + int fSpecial; DirectoryCacheSnapshot* fSnapshot; NameCacheEntry* fCurrent; bool fEOF; diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp b/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp index 05af489268..2c84afbd69 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp @@ -122,6 +122,7 @@ Inode::OpenDir(OpenDirCookie* cookie) return B_PERMISSION_DENIED; cookie->fFileSystem = fFileSystem; + cookie->fSpecial = 0; cookie->fSnapshot = NULL; cookie->fCurrent = NULL; cookie->fEOF = false; @@ -334,30 +335,6 @@ Inode::_GetDirSnapshot(DirectoryCacheSnapshot** _snapshot, return B_OK; } -/* - if (cookie->fCookie == 0 && cookie->fCookieVerf == 2 && count < *_count) { - struct dirent* de = reinterpret_cast(buffer + pos); - - _FillDirEntry(de, fInfo.fFileId, ".", pos, size); - - pos += de->d_reclen; - count++; - cookie->fCookieVerf--; - } - - if (cookie->fCookie == 0 && cookie->fCookieVerf == 1 && count < *_count) { - struct dirent* de = reinterpret_cast(buffer + pos); - - if (strcmp(fInfo.fName, "/")) - _ReadDirUp(de, pos, size); - else - _FillDirEntry(de, _FileIdToInoT(fInfo.fFileId), "..", pos, size); - - pos += de->d_reclen; - count++; - cookie->fCookieVerf--; - } -*/ status_t Inode::ReadDir(void* _buffer, uint32 size, uint32* _count, @@ -397,11 +374,46 @@ Inode::ReadDir(void* _buffer, uint32 size, uint32* _count, char* buffer = reinterpret_cast(_buffer); uint32 pos = 0; + uint32 i = 0; + bool overflow = false; + + if (cookie->fSpecial == 0 && i < *_count) { + struct dirent* de = reinterpret_cast(buffer + pos); + + status_t result; + result = _FillDirEntry(de, fInfo.fFileId, ".", pos, size); + + if (result == B_BUFFER_OVERFLOW) + overflow = true; + else if (result == B_OK) { + pos += de->d_reclen; + i++; + cookie->fSpecial++; + } else + return result; + } + + if (cookie->fSpecial == 1 && i < *_count) { + struct dirent* de = reinterpret_cast(buffer + pos); + + status_t result; + if (strcmp(fInfo.fName, "/")) + result = _ReadDirUp(de, pos, size); + else + result = _FillDirEntry(de, _FileIdToInoT(fInfo.fFileId), "..", pos, size); + + if (result == B_BUFFER_OVERFLOW) + overflow = true; + else if (result == B_OK) { + pos += de->d_reclen; + i++; + cookie->fSpecial++; + } else + return result; + } MutexLocker _(cookie->fSnapshot->fLock); - uint32 i; - bool overflow = false; - for (i = 0; i < *_count; i++) { + for (; !overflow && i < *_count; i++) { struct dirent* de = reinterpret_cast(buffer + pos); if (cookie->fCurrent == NULL) From 7cac2f6e50588ad130d2770ada1b1981569a1602 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Fri, 20 Jul 2012 04:09:16 +0200 Subject: [PATCH 144/252] nfs4: Local creation of node should not invalidate the cache --- .../file_systems/nfs4/DirectoryCache.cpp | 17 +++- .../kernel/file_systems/nfs4/DirectoryCache.h | 4 +- .../kernel/file_systems/nfs4/Inode.cpp | 78 ++++++++++++++++--- .../kernel/file_systems/nfs4/InodeDir.cpp | 22 +++++- 4 files changed, 105 insertions(+), 16 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.cpp b/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.cpp index a3065aa286..dbb10f0c50 100644 --- a/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.cpp @@ -87,9 +87,9 @@ DirectoryCache::Trash() fTrashed = true; } -// TODO: separate AddEntry() for Name and Directory Cache are needed + status_t -DirectoryCache::AddEntry(const char* name, ino_t node) +DirectoryCache::AddEntry(const char* name, ino_t node, bool created) { NameCacheEntry* entry = new(std::nothrow) NameCacheEntry(name, node); if (entry == NULL) @@ -101,6 +101,19 @@ DirectoryCache::AddEntry(const char* name, ino_t node) fNameCache.Add(entry); + if (created && fDirectoryCache != NULL) { + MutexLocker _(fDirectoryCache->fLock); + NameCacheEntry* entry = new(std::nothrow) NameCacheEntry(name, node); + if (entry == NULL) + return B_NO_MEMORY; + if (entry->fName == NULL) { + delete entry; + return B_NO_MEMORY; + } + + fDirectoryCache->fEntries.Add(entry); + } + return entry_cache_add(fInode->GetFileSystem()->DevId(), fInode->ID(), name, node); } diff --git a/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.h b/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.h index 0e9b07ba13..9e880f67ff 100644 --- a/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.h +++ b/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.h @@ -46,7 +46,8 @@ public: void ResetAndLock(); void Trash(); - status_t AddEntry(const char* name, ino_t node); + status_t AddEntry(const char* name, ino_t node, + bool created = false); void RemoveEntry(const char* name); void SetSnapshot(DirectoryCacheSnapshot* snapshot); @@ -68,7 +69,6 @@ private: SinglyLinkedList fNameCache; DirectoryCacheSnapshot* fDirectoryCache; - //mutex fDirectoryCacheLock; Inode* fInode; diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index f49a0c2f25..3d87f3662b 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -281,6 +281,10 @@ Inode::Link(Inode* dir, const char* name) req.PutFH(dir->fInfo.fHandle); req.Link(name); + req.LookUp(name); + Attribute attr[] = { FATTR4_FILEID }; + req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); + status_t result = request.Send(); if (result != B_OK) return result; @@ -310,10 +314,27 @@ Inode::Link(Inode* dir, const char* name) if (result != B_OK) return result; + result = reply.LookUp(); + 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[1].fData.fValue64; + + fFileSystem->Root()->MakeInfoInvalid(); + if (fCache->Lock() == B_OK) { if (atomic && fCache->ChangeInfo() == before) { - // TODO: update cache - //fCache->AddEntry(name, ); + fCache->AddEntry(name, fileID, true); fCache->SetChangeInfo(after); } else if (fCache->ChangeInfo() != before) fCache->Trash(); @@ -418,6 +439,10 @@ Inode::Rename(Inode* from, Inode* to, const char* fromName, const char* toName) req.PutFH(to->fInfo.fHandle); req.Rename(fromName, toName); + Attribute attr[] = { FATTR4_FILEID }; + req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); + req.LookUp(toName); + status_t result = request.Send(); if (result != B_OK) return result; @@ -445,6 +470,26 @@ Inode::Rename(Inode* from, Inode* to, const char* fromName, const char* toName) bool fromAtomic, toAtomic; result = reply.Rename(&fromBefore, &fromAfter, fromAtomic, &toBefore, &toAfter, toAtomic); + if (result != B_OK) + return result; + + result = reply.LookUp(); + 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 = from->fFileSystem->AllocFileId(); + else + fileID = values[1].fData.fValue64; + + from->fFileSystem->Root()->MakeInfoInvalid(); if (from->fCache->Lock() == B_OK) { if (fromAtomic && from->fCache->ChangeInfo() == fromBefore) { @@ -457,15 +502,14 @@ Inode::Rename(Inode* from, Inode* to, const char* fromName, const char* toName) if (to->fCache->Lock() == B_OK) { if (toAtomic && to->fCache->ChangeInfo() == toBefore) { - // TODO: update cache - //fCache->AddEntry(toName, ); + to->fCache->AddEntry(toName, fileID, true); to->fCache->SetChangeInfo(toAfter); } else if (to->fCache->ChangeInfo() != toBefore) to->fCache->Trash(); to->fCache->Unlock(); - }; + } - return result; + return B_OK; } while (true); } @@ -505,6 +549,9 @@ Inode::CreateLink(const char* name, const char* path, int mode) req.Create(NF4LNK, name, cattr, i, path); + Attribute attr[] = { FATTR4_FILEID }; + req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); + status_t result = request.Send(); if (result != B_OK) return result; @@ -523,20 +570,33 @@ Inode::CreateLink(const char* name, const char* path, int mode) uint64 before, after; bool atomic; result = reply.Create(&before, &after, atomic); + 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[1].fData.fValue64; fFileSystem->Root()->MakeInfoInvalid(); if (fCache->Lock() == B_OK) { if (atomic && fCache->ChangeInfo() == before) { - // TODO: update cache - //fCache->AddEntry(name, ); + fCache->AddEntry(name, fileID, true); fCache->SetChangeInfo(after); } else if (fCache->ChangeInfo() != before) fCache->Trash(); fCache->Unlock(); } - return result; + return B_OK; } while (true); } diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp b/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp index 2c84afbd69..28addc3171 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp @@ -52,6 +52,9 @@ Inode::CreateDir(const char* name, int mode) req.Create(NF4DIR, name, cattr, i); + Attribute attr[] = { FATTR4_FILEID }; + req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); + status_t result = request.Send(); if (result != B_OK) return result; @@ -70,20 +73,33 @@ Inode::CreateDir(const char* name, int mode) uint64 before, after; bool atomic; result = reply.Create(&before, &after, atomic); + 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[1].fData.fValue64; fFileSystem->Root()->MakeInfoInvalid(); if (fCache->Lock() == B_OK) { if (atomic && fCache->ChangeInfo() == before) { - // TODO: update cache - //fCache->AddEntry(name, ); + fCache->AddEntry(name, fileID, true); fCache->SetChangeInfo(after); } else if (fCache->ChangeInfo() != before) fCache->Trash(); fCache->Unlock(); } - return result; + return B_OK; } while (true); } From df6a5eaefa0e549032f0a58e9191679f2c1eb60c Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Wed, 25 Jul 2012 03:45:52 +0200 Subject: [PATCH 145/252] nfs4: Fix several issues introduced in previous commits --- .../kernel/file_systems/nfs4/Inode.cpp | 114 ++++++++++-------- src/add-ons/kernel/file_systems/nfs4/Inode.h | 3 + .../kernel/file_systems/nfs4/InodeDir.cpp | 12 +- .../kernel/file_systems/nfs4/InodeRegular.cpp | 20 ++- .../file_systems/nfs4/ReplyInterpreter.cpp | 18 ++- .../file_systems/nfs4/ReplyInterpreter.h | 4 +- 6 files changed, 114 insertions(+), 57 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index 3d87f3662b..b87792ece7 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -229,25 +229,9 @@ Inode::LookUp(const char* name, ino_t* id) *id = _FileIdToInoT(fileId); - FileInfo fi; - fi.fFileId = fileId; - fi.fHandle = fh; - fi.fParent = fInfo.fHandle; - fi.fName = strdup(name); - if (fi.fName == NULL) - return B_NO_MEMORY; - - char* path = reinterpret_cast(malloc(strlen(name) + 2 + - strlen(fInfo.fPath))); - if (path == NULL) - return B_NO_MEMORY; - - strcpy(path, fInfo.fPath); - strcat(path, "/"); - strcat(path, name); - fi.fPath = path; - - fFileSystem->InoIdMap()->AddEntry(fi, *id); + result = _ChildAdded(name, fileId, fh); + if (result != B_OK) + return result; fFileSystem->Revalidator().Lock(); if (fCache->Lock() != B_OK) { @@ -281,10 +265,6 @@ Inode::Link(Inode* dir, const char* name) req.PutFH(dir->fInfo.fHandle); req.Link(name); - req.LookUp(name); - Attribute attr[] = { FATTR4_FILEID }; - req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); - status_t result = request.Send(); if (result != B_OK) return result; @@ -314,31 +294,35 @@ Inode::Link(Inode* dir, const char* name) if (result != B_OK) return result; - result = reply.LookUp(); - 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[1].fData.fValue64; - fFileSystem->Root()->MakeInfoInvalid(); - 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(); + FileInfo fi = fInfo; + fi.fParent = dir->fInfo.fHandle; + free(const_cast(fi.fName)); + fi.fName = strdup(name); + if (fi.fName == NULL) + return B_NO_MEMORY; + + char* path = reinterpret_cast(malloc(strlen(name) + 2 + + strlen(fInfo.fPath))); + if (path == NULL) + return B_NO_MEMORY; + + strcpy(path, dir->fInfo.fPath); + strcat(path, "/"); + strcat(path, name); + free(const_cast(fi.fPath)); + fi.fPath = path; + + fFileSystem->InoIdMap()->AddEntry(fi, fInfo.fFileId); + + if (dir->fCache->Lock() == B_OK) { + if (atomic && dir->fCache->ChangeInfo() == before) { + dir->fCache->AddEntry(name, fInfo.fFileId, true); + dir->fCache->SetChangeInfo(after); + } else if (dir->fCache->ChangeInfo() != before) + dir->fCache->Trash(); + dir->fCache->Unlock(); } return B_OK; @@ -549,6 +533,7 @@ Inode::CreateLink(const char* name, const char* path, int mode) req.Create(NF4LNK, name, cattr, i, path); + req.GetFH(); Attribute attr[] = { FATTR4_FILEID }; req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); @@ -573,6 +558,9 @@ Inode::CreateLink(const char* name, const char* path, int mode) if (result != B_OK) return result; + FileHandle handle; + reply.GetFH(&handle); + AttrValue* values; uint32 count; result = reply.GetAttr(&values, &count); @@ -583,10 +571,14 @@ Inode::CreateLink(const char* name, const char* path, int mode) if (count == 0) fileID = fFileSystem->AllocFileId(); else - fileID = values[1].fData.fValue64; + fileID = values[0].fData.fValue64; fFileSystem->Root()->MakeInfoInvalid(); + 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); @@ -1310,3 +1302,31 @@ Inode::_HandleErrors(uint32 nfs4Error, RPC::Server* serv, } } + +status_t +Inode::_ChildAdded(const char* name, uint64 fileID, + const FileHandle& fileHandle) +{ + fFileSystem->Root()->MakeInfoInvalid(); + + FileInfo fi; + fi.fFileId = fileID; + fi.fHandle = fileHandle; + fi.fParent = fInfo.fHandle; + fi.fName = strdup(name); + if (fi.fName == NULL) + return B_NO_MEMORY; + + char* path = reinterpret_cast(malloc(strlen(name) + 2 + + strlen(fInfo.fPath))); + if (path == NULL) + return B_NO_MEMORY; + + strcpy(path, fInfo.fPath); + strcat(path, "/"); + strcat(path, name); + fi.fPath = path; + + return fFileSystem->InoIdMap()->AddEntry(fi, _FileIdToInoT(fileID)); +} + diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h b/src/add-ons/kernel/file_systems/nfs4/Inode.h index feb9964c94..6a7a584bca 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -92,6 +92,9 @@ protected: _snapshot, OpenDirCookie* cookie, uint64* _change); + status_t _ChildAdded(const char* name, uint64 fileID, + const FileHandle& fileHandle); + static inline status_t _CheckLockType(short ltype, uint32 mode); static inline ino_t _FileIdToInoT(uint64 fileid); diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp b/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp index 28addc3171..e12ab4c97e 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp @@ -52,6 +52,7 @@ Inode::CreateDir(const char* name, int mode) req.Create(NF4DIR, name, cattr, i); + req.GetFH(); Attribute attr[] = { FATTR4_FILEID }; req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); @@ -76,6 +77,11 @@ Inode::CreateDir(const char* name, int mode) 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); @@ -86,9 +92,11 @@ Inode::CreateDir(const char* name, int mode) if (count == 0) fileID = fFileSystem->AllocFileId(); else - fileID = values[1].fData.fValue64; + fileID = values[0].fData.fValue64; - fFileSystem->Root()->MakeInfoInvalid(); + result = _ChildAdded(name, fileID, handle); + if (result != B_OK) + return B_OK; if (fCache->Lock() == B_OK) { if (atomic && fCache->ChangeInfo() == before) { diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp index 9c7c83d491..ace10fa343 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp @@ -132,7 +132,14 @@ Inode::Create(const char* name, int mode, int perms, OpenFileCookie* cookie, continue; reply.PutFH(); - reply.Open(cookie->fStateId, &cookie->fStateSeq, &confirm); + + 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; @@ -143,7 +150,7 @@ Inode::Create(const char* name, int mode, int perms, OpenFileCookie* cookie, if (result != B_OK) return result; - fileId = values[1].fData.fValue64; + fileId = values[0].fData.fValue64; delete[] values; } else @@ -166,6 +173,15 @@ Inode::Create(const char* name, int mode, int perms, OpenFileCookie* cookie, 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; diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp index c80b5da395..0fdf732f0b 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp @@ -135,8 +135,9 @@ ReplyInterpreter::Create(uint64* before, uint64* after, bool& atomic) atomic = fReply->Stream().GetBoolean(); *before = fReply->Stream().GetUHyper(); *after = fReply->Stream().GetUHyper(); + uint32 count = fReply->Stream().GetUInt(); - for (uint32 i; i < count; i++) + for (uint32 i = 0; i < count; i++) fReply->Stream().GetUInt(); return fReply->Stream().IsEOF() ? B_BAD_VALUE : B_OK; @@ -252,7 +253,8 @@ ReplyInterpreter::LockU(LockInfo* linfo) status_t -ReplyInterpreter::Open(uint32* id, uint32* seq, bool* confirm) +ReplyInterpreter::Open(uint32* id, uint32* seq, bool* confirm, uint64* _before, + uint64* _after, bool* _atomic) { status_t res = _OperationError(OpOpen); if (res != B_OK) @@ -264,9 +266,15 @@ ReplyInterpreter::Open(uint32* id, uint32* seq, bool* confirm) id[2] = fReply->Stream().GetUInt(); // change info - fReply->Stream().GetBoolean(); - fReply->Stream().GetUHyper(); - fReply->Stream().GetUHyper(); + bool atomic = fReply->Stream().GetBoolean(); + if (_atomic != NULL) + *_atomic = atomic; + uint64 before = fReply->Stream().GetUHyper(); + if (_before != NULL) + *_before = before; + uint64 after = fReply->Stream().GetUHyper(); + if (_after != NULL) + *_after = after; uint32 flags = fReply->Stream().GetUInt(); *confirm = (flags & OPEN4_RESULT_CONFIRM) == OPEN4_RESULT_CONFIRM; diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h index 92739d2f95..27a60d73b4 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h @@ -79,7 +79,9 @@ public: inline status_t LookUp(); inline status_t LookUpUp(); inline status_t Nverify(); - status_t Open(uint32* id, uint32* seq, bool* confirm); + status_t Open(uint32* id, uint32* seq, bool* confirm, + uint64* before = NULL, uint64* after = NULL, + bool* atomic = NULL); status_t OpenConfirm(uint32* stateSeq); inline status_t PutFH(); inline status_t PutRootFH(); From b5162ff580a35f428ca39bd8beb1c2711c9b820f Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Wed, 25 Jul 2012 03:58:32 +0200 Subject: [PATCH 146/252] nfs4: Apparently DoublyLinkedQueue is not a queue --- src/add-ons/kernel/file_systems/nfs4/CacheRevalidator.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/CacheRevalidator.h b/src/add-ons/kernel/file_systems/nfs4/CacheRevalidator.h index 86322d4e65..b3bfed9541 100644 --- a/src/add-ons/kernel/file_systems/nfs4/CacheRevalidator.h +++ b/src/add-ons/kernel/file_systems/nfs4/CacheRevalidator.h @@ -11,7 +11,7 @@ #include #include -#include +#include #include "DirectoryCache.h" @@ -37,7 +37,7 @@ private: bool fThreadCancel; sem_id fWaitCancel; - DoublyLinkedQueue fDirectoryCaches; + DoublyLinkedList fDirectoryCaches; mutex fDirectoryCachesLock; }; @@ -58,7 +58,7 @@ CacheRevalidator::Unlock() inline void CacheRevalidator::AddDirectory(DirectoryCache* cache) { - fDirectoryCaches.Add(cache); + fDirectoryCaches.InsertAfter(fDirectoryCaches.Tail(), cache); } From 0bc98afd433d6b193773d937c06048b4ade01cd6 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Fri, 27 Jul 2012 01:53:54 +0200 Subject: [PATCH 147/252] nfs4: Basic data cache implementation --- .../kernel/file_systems/nfs4/Inode.cpp | 29 +++-- src/add-ons/kernel/file_systems/nfs4/Inode.h | 12 +- .../kernel/file_systems/nfs4/InodeRegular.cpp | 10 +- .../kernel/file_systems/nfs4/RootInode.cpp | 22 ++-- .../kernel/file_systems/nfs4/RootInode.h | 13 +++ .../file_systems/nfs4/kernel_interface.cpp | 107 ++++++++++++++++-- 6 files changed, 160 insertions(+), 33 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index b87792ece7..607df773de 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -12,6 +12,7 @@ #include #include +#include #include #include "IdMap.h" @@ -22,7 +23,8 @@ Inode::Inode() : fAttrCacheExpire(0), - fCache(NULL) + fCache(NULL), + fFileCache(NULL) { mutex_init(&fAttrCacheLock, NULL); } @@ -43,6 +45,7 @@ Inode::CreateInode(FileSystem* fs, const FileInfo &fi, Inode** _inode) inode->fInfo = fi; inode->fFileSystem = fs; + uint64 size; do { RPC::Server* serv = fs->Server(); Request request(serv); @@ -50,7 +53,8 @@ Inode::CreateInode(FileSystem* fs, const FileInfo &fi, Inode** _inode) req.PutFH(inode->fInfo.fHandle); - Attribute attr[] = { FATTR4_TYPE, FATTR4_FSID, FATTR4_FILEID }; + Attribute attr[] = { FATTR4_TYPE, FATTR4_SIZE, FATTR4_FSID, + FATTR4_FILEID }; req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); status_t result = request.Send(); @@ -67,14 +71,14 @@ Inode::CreateInode(FileSystem* fs, const FileInfo &fi, Inode** _inode) AttrValue* values; uint32 count; result = reply.GetAttr(&values, &count); - if (result != B_OK || count < 2) + if (result != B_OK || count < 3) return result; if (fi.fFileId == 0) { - if (count < 3 || values[2].fAttribute != FATTR4_FILEID) + if (count < 4 || values[3].fAttribute != FATTR4_FILEID) inode->fInfo.fFileId = fs->AllocFileId(); else - inode->fInfo.fFileId = values[2].fData.fValue64; + inode->fInfo.fFileId = values[3].fData.fValue64; } else inode->fInfo.fFileId = fi.fFileId; @@ -84,9 +88,12 @@ Inode::CreateInode(FileSystem* fs, const FileInfo &fi, Inode** _inode) if (inode->fType == NF4DIR) inode->fCache = new DirectoryCache(inode); + // FATTR4_SIZE is mandatory + size = values[1].fData.fValue64; + // FATTR4_FSID is mandatory FileSystemId* fsid = - reinterpret_cast(values[1].fData.fPointer); + reinterpret_cast(values[2].fData.fPointer); if (*fsid != fs->FsId()) { delete[] values; return B_ENTRY_NOT_FOUND; @@ -96,13 +103,21 @@ Inode::CreateInode(FileSystem* fs, const FileInfo &fi, Inode** _inode) *_inode = inode; - return B_OK; + break; } while (true); + + if (inode->fType == NF4REG) + inode->fFileCache = file_cache_create(fs->DevId(), inode->ID(), size); + + return B_OK; } Inode::~Inode() { + if (fFileCache != NULL) + file_cache_delete(fFileCache); + delete fCache; mutex_destroy(&fAttrCacheLock); } diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h b/src/add-ons/kernel/file_systems/nfs4/Inode.h index 6a7a584bca..110efa83bf 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -30,6 +30,8 @@ public: inline const char* Name() const; inline FileSystem* GetFileSystem() const; + inline void* FileCache(); + status_t GetChangeInfo(uint64* change); status_t LookUp(const char* name, ino_t* id); @@ -52,7 +54,7 @@ public: status_t Open(int mode, OpenFileCookie* cookie); status_t Close(OpenFileCookie* cookie); status_t Read(OpenFileCookie* cookie, off_t pos, - void* buffer, size_t* length); + void* buffer, size_t* length, bool* eof); status_t Write(OpenFileCookie* cookie, off_t pos, const void* buffer, size_t *_length); @@ -111,6 +113,7 @@ protected: FileSystem* fFileSystem; DirectoryCache* fCache; + void* fFileCache; }; @@ -153,5 +156,12 @@ Inode::GetFileSystem() const } +inline void* +Inode::FileCache() +{ + return fFileCache; +} + + #endif // INODE_H diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp index ace10fa343..f6718f1b1c 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp @@ -11,6 +11,7 @@ #include +#include #include #include "IdMap.h" @@ -330,13 +331,14 @@ Inode::Close(OpenFileCookie* cookie) status_t -Inode::Read(OpenFileCookie* cookie, off_t pos, void* buffer, size_t* _length) +Inode::Read(OpenFileCookie* cookie, off_t pos, void* buffer, size_t* _length, + bool* eof) { - bool eof = false; + *eof = false; uint32 size = 0; uint32 len = 0; - while (size < *_length && !eof) { + while (size < *_length && !*eof) { do { RPC::Server* serv = fFileSystem->Server(); Request request(serv); @@ -357,7 +359,7 @@ Inode::Read(OpenFileCookie* cookie, off_t pos, void* buffer, size_t* _length) reply.PutFH(); result = reply.Read(reinterpret_cast(buffer) + size, &len, - &eof); + eof); if (result != B_OK) return result; diff --git a/src/add-ons/kernel/file_systems/nfs4/RootInode.cpp b/src/add-ons/kernel/file_systems/nfs4/RootInode.cpp index 82a0340400..6d99f30812 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RootInode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RootInode.cpp @@ -16,7 +16,8 @@ RootInode::RootInode() : - fInfoCacheExpire(0) + fInfoCacheExpire(0), + fIOSize(0) { mutex_init(&fInfoCacheLock, NULL); } @@ -90,29 +91,30 @@ RootInode::_UpdateInfo(bool force) next++; } - uint64 io_size = LONGLONG_MAX; + uint64 ioSize = LONGLONG_MAX; if (count >= next && values[next].fAttribute == FATTR4_MAXREAD) { - io_size = min_c(io_size, values[next].fData.fValue64); + ioSize = min_c(ioSize, values[next].fData.fValue64); next++; } if (count >= next && values[next].fAttribute == FATTR4_MAXWRITE) { - io_size = min_c(io_size, values[next].fData.fValue64); + ioSize = min_c(ioSize, values[next].fData.fValue64); next++; } - if (io_size == LONGLONG_MAX) - io_size = 32768; - fInfoCache.io_size = io_size; - fInfoCache.block_size = io_size; + if (ioSize == LONGLONG_MAX) + ioSize = 32768; + fInfoCache.io_size = ioSize; + fInfoCache.block_size = ioSize; + fIOSize = ioSize; if (count >= next && values[next].fAttribute == FATTR4_SPACE_FREE) { - fInfoCache.free_blocks = values[next].fData.fValue64 / io_size; + fInfoCache.free_blocks = values[next].fData.fValue64 / ioSize; next++; } if (count >= next && values[next].fAttribute == FATTR4_SPACE_TOTAL) { - fInfoCache.total_blocks = values[next].fData.fValue64 / io_size; + fInfoCache.total_blocks = values[next].fData.fValue64 / ioSize; next++; } diff --git a/src/add-ons/kernel/file_systems/nfs4/RootInode.h b/src/add-ons/kernel/file_systems/nfs4/RootInode.h index 5b01b89ff5..864d49ddba 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RootInode.h +++ b/src/add-ons/kernel/file_systems/nfs4/RootInode.h @@ -22,6 +22,8 @@ public: status_t ReadInfo(struct fs_info* info); inline void MakeInfoInvalid(); + inline uint32 IOSize(); + bool ProbeMigration(); status_t GetLocations(AttrValue** attr); @@ -30,6 +32,8 @@ private: mutex fInfoCacheLock; time_t fInfoCacheExpire; + uint32 fIOSize; + status_t _UpdateInfo(bool force = false); }; @@ -42,5 +46,14 @@ RootInode::MakeInfoInvalid() } +inline uint32 +RootInode::IOSize() +{ + if (fIOSize == 0) + _UpdateInfo(true); + return fIOSize; +} + + #endif // ROOTINODE_H 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 fdd79f3d11..391b57dc2a 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -9,6 +9,7 @@ #include +#include #include #include "Connection.h" @@ -212,6 +213,59 @@ nfs4_remove_vnode(fs_volume* volume, fs_vnode* vnode, bool reenter) } +static status_t +nfs4_read_pages(fs_volume* _volume, fs_vnode* vnode, void* _cookie, off_t pos, + const iovec* vecs, size_t count, size_t* _numBytes) +{ + Inode* inode = reinterpret_cast(vnode->private_node); + OpenFileCookie* cookie = reinterpret_cast(_cookie); + + status_t result; + bool eof = false; + for (size_t i = 0; i < count && !eof; i++) { + size_t bytesLeft = vecs[i].iov_len; + char* buffer = reinterpret_cast(vecs[i].iov_base); + + do { + size_t bytesRead = bytesLeft; + result = inode->Read(cookie, pos, buffer, &bytesRead, &eof); + if (result != B_OK) + return result; + + pos += bytesRead; + buffer += bytesRead; + bytesLeft -= bytesRead; + } while (bytesLeft > 0 && !eof); + } + + return B_OK; +} + + +static status_t +nfs4_write_pages(fs_volume* _volume, fs_vnode* vnode, void* _cookie, off_t pos, + const iovec* vecs, size_t count, size_t* _numBytes) +{ + return B_OK; +} + + +static status_t +nfs4_io(fs_volume* volume, fs_vnode* vnode, void* cookie, io_request* request) +{ + // no asynchronous calls yet + return B_UNSUPPORTED; +} + + +static status_t +nfs4_get_file_map(fs_volume* volume, fs_vnode* vnode, off_t _offset, + size_t size, struct file_io_vec* vecs, size_t* _count) +{ + return B_ERROR; +} + + static status_t nfs4_set_flags(fs_volume* volume, fs_vnode* vnode, void* _cookie, int flags) { @@ -224,7 +278,7 @@ nfs4_set_flags(fs_volume* volume, fs_vnode* vnode, void* _cookie, int flags) static status_t nfs4_fsync(fs_volume* volume, fs_vnode* vnode) { - // Currently, there is no cache and all writes are FILE_SYNC4 + // Currently all writes are FILE_SYNC4 return B_OK; } @@ -378,7 +432,7 @@ nfs4_free_cookie(fs_volume* volume, fs_vnode* vnode, void* _cookie) static status_t -nfs4_read(fs_volume* volume, fs_vnode* vnode, void* _cookie, off_t pos, +nfs4_read(fs_volume* volume, fs_vnode* vnode, void* cookie, off_t pos, void* buffer, size_t* length) { Inode* inode = reinterpret_cast(vnode->private_node); @@ -389,15 +443,13 @@ nfs4_read(fs_volume* volume, fs_vnode* vnode, void* _cookie, off_t pos, if (inode->Type() == S_IFLNK) return B_BAD_VALUE; - OpenFileCookie* cookie = reinterpret_cast(_cookie); - - return inode->Read(cookie, pos, buffer, length); + return file_cache_read(inode->FileCache(), cookie, pos, buffer, length); } static status_t nfs4_write(fs_volume* volume, fs_vnode* vnode, void* _cookie, off_t pos, - const void* buffer, size_t* length) + const void* _buffer, size_t* length) { Inode* inode = reinterpret_cast(vnode->private_node); @@ -409,7 +461,40 @@ nfs4_write(fs_volume* volume, fs_vnode* vnode, void* _cookie, off_t pos, OpenFileCookie* cookie = reinterpret_cast(_cookie); - return inode->Write(cookie, pos, buffer, length); + struct stat stat; + status_t result = inode->Stat(&stat); + if (result != B_OK) + return result; + + uint64 fileSize = max_c(stat.st_size, pos + *length); + result = file_cache_set_size(inode->FileCache(), fileSize); + if (result != B_OK) + return result; + + result = file_cache_write(inode->FileCache(), cookie, pos, _buffer, + length); + if (result != B_OK) + return result; + + uint32 ioSize = inode->GetFileSystem()->Root()->IOSize(); + size_t bytesLeft = *length; + const char* buffer = reinterpret_cast(_buffer); + do { + size_t bytesWritten = min_c(ioSize, bytesLeft); + result = inode->Write(cookie, pos, buffer, &bytesWritten); + if (result != B_OK) + break; + + bytesLeft -= bytesWritten; + pos += bytesWritten; + buffer += bytesWritten; + } while (bytesLeft > 0); + + if (bytesLeft == *length) + return result; + + *length = *length - bytesLeft; + return B_OK; } @@ -582,13 +667,13 @@ fs_vnode_ops gNFSv4VnodeOps = { /* VM file access */ NULL, // can_page() - NULL, // read_pages() - NULL, // write_pages() + nfs4_read_pages, + nfs4_write_pages, - NULL, // io() + nfs4_io, NULL, // cancel_io() - NULL, // get_file_map() + nfs4_get_file_map, NULL, // ioctl() nfs4_set_flags, From be4499d19e0c76b87912cd497d945374dc84e294 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Fri, 27 Jul 2012 02:23:40 +0200 Subject: [PATCH 148/252] nfs4: Change write policy from write through to write back --- .../kernel/file_systems/nfs4/InodeRegular.cpp | 3 +- .../file_systems/nfs4/kernel_interface.cpp | 77 ++++++++++++------- 2 files changed, 53 insertions(+), 27 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp index f6718f1b1c..c55210d7ce 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp @@ -323,7 +323,7 @@ Inode::Close(OpenFileCookie* cookie) if (result != B_OK) return result; - return B_OK; + break; } while (true); return B_OK; @@ -450,6 +450,7 @@ Inode::Write(OpenFileCookie* cookie, off_t pos, const void* _buffer, *_length = size; + fAttrCache.st_size = max_c(fAttrCache.st_size, *_length + pos); fFileSystem->Root()->MakeInfoInvalid(); return B_OK; 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 391b57dc2a..15c0d00590 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -246,6 +246,53 @@ static status_t nfs4_write_pages(fs_volume* _volume, fs_vnode* vnode, void* _cookie, off_t pos, const iovec* vecs, size_t count, size_t* _numBytes) { + Inode* inode = reinterpret_cast(vnode->private_node); + bool freeCookie = false; + OpenFileCookie* cookie = reinterpret_cast(_cookie); + + if (cookie == NULL) { + cookie = new OpenFileCookie; + if (cookie == NULL) + return B_NO_MEMORY; + + status_t result = inode->Open(O_WRONLY, cookie); + if (result != B_OK) { + delete cookie; + return result; + } + + freeCookie = true; + } + + status_t result; + uint32 ioSize = inode->GetFileSystem()->Root()->IOSize(); + for (size_t i = 0; i < count; i++) { + size_t bytesLeft = vecs[i].iov_len; + char* buffer = reinterpret_cast(vecs[i].iov_base); + + do { + size_t bytesWritten = min_c(ioSize, bytesLeft); + + result = inode->Write(cookie, pos, buffer, &bytesWritten); + if (result != B_OK) { + if (freeCookie) { + inode->Close(cookie); + delete cookie; + } + return result; + } + + bytesLeft -= bytesWritten; + pos += bytesWritten; + buffer += bytesWritten; + } while (bytesLeft > 0); + } + + if (freeCookie) { + inode->Close(cookie); + delete cookie; + } + return B_OK; } @@ -278,8 +325,8 @@ nfs4_set_flags(fs_volume* volume, fs_vnode* vnode, void* _cookie, int flags) static status_t nfs4_fsync(fs_volume* volume, fs_vnode* vnode) { - // Currently all writes are FILE_SYNC4 - return B_OK; + Inode* inode = reinterpret_cast(vnode->private_node); + return file_cache_sync(inode->FileCache()); } @@ -424,6 +471,7 @@ nfs4_free_cookie(fs_volume* volume, fs_vnode* vnode, void* _cookie) return B_OK; OpenFileCookie* cookie = reinterpret_cast(_cookie); + file_cache_sync(inode->FileCache()); inode->Close(cookie); delete cookie; @@ -471,30 +519,7 @@ nfs4_write(fs_volume* volume, fs_vnode* vnode, void* _cookie, off_t pos, if (result != B_OK) return result; - result = file_cache_write(inode->FileCache(), cookie, pos, _buffer, - length); - if (result != B_OK) - return result; - - uint32 ioSize = inode->GetFileSystem()->Root()->IOSize(); - size_t bytesLeft = *length; - const char* buffer = reinterpret_cast(_buffer); - do { - size_t bytesWritten = min_c(ioSize, bytesLeft); - result = inode->Write(cookie, pos, buffer, &bytesWritten); - if (result != B_OK) - break; - - bytesLeft -= bytesWritten; - pos += bytesWritten; - buffer += bytesWritten; - } while (bytesLeft > 0); - - if (bytesLeft == *length) - return result; - - *length = *length - bytesLeft; - return B_OK; + return file_cache_write(inode->FileCache(), cookie, pos, _buffer, length); } From 36577ed54ba11c2e9b1a61f66cc2a704e2af7697 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Fri, 27 Jul 2012 03:08:46 +0200 Subject: [PATCH 149/252] nfs4: Use unstable writes and commit before close --- src/add-ons/kernel/file_systems/nfs4/Inode.h | 2 ++ .../kernel/file_systems/nfs4/InodeRegular.cpp | 26 +++++++++++++++++++ .../kernel/file_systems/nfs4/NFS4Defs.h | 1 + .../file_systems/nfs4/ReplyInterpreter.cpp | 13 ++++++++++ .../file_systems/nfs4/ReplyInterpreter.h | 1 + .../file_systems/nfs4/RequestBuilder.cpp | 20 +++++++++++++- .../kernel/file_systems/nfs4/RequestBuilder.h | 1 + .../file_systems/nfs4/kernel_interface.cpp | 1 + 8 files changed, 64 insertions(+), 1 deletion(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h b/src/add-ons/kernel/file_systems/nfs4/Inode.h index 110efa83bf..692bfec298 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -34,6 +34,8 @@ public: status_t GetChangeInfo(uint64* change); + status_t Commit(); + status_t LookUp(const char* name, ino_t* id); status_t CreateLink(const char* name, const char* path, diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp index c55210d7ce..c1f6bf86ab 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp @@ -456,3 +456,29 @@ Inode::Write(OpenFileCookie* cookie, off_t pos, const void* _buffer, return B_OK; } + +status_t +Inode::Commit() +{ + do { + RPC::Server* serv = fFileSystem->Server(); + Request request(serv); + RequestBuilder& req = request.Builder(); + + 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); +} + diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h index 31e82c2670..8ba791de2a 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h @@ -23,6 +23,7 @@ enum Procedure { enum Opcode { OpAccess = 3, OpClose = 4, + OpCommit = 5, OpCreate = 6, OpGetAttr = 9, OpGetFH = 10, diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp index 0fdf732f0b..56ba582894 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp @@ -125,6 +125,19 @@ ReplyInterpreter::Close() } +status_t +ReplyInterpreter::Commit() +{ + status_t res = _OperationError(OpCommit); + if (res != B_OK) + return res; + + fReply->Stream().GetOpaque(NULL); + + return fReply->Stream().IsEOF() ? B_BAD_VALUE : B_OK; +} + + status_t ReplyInterpreter::Create(uint64* before, uint64* after, bool& atomic) { diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h index 27a60d73b4..ed3a2695a1 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h @@ -69,6 +69,7 @@ public: status_t Access(uint32* supported, uint32* allowed); status_t Close(); + status_t Commit(); status_t Create(uint64* before, uint64* after, bool& atomic); status_t GetAttr(AttrValue** attrs, uint32* count); status_t GetFH(FileHandle* fh); diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp index 738f854d75..d4b676cf00 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp @@ -89,6 +89,24 @@ RequestBuilder::Close(uint32 seq, const uint32* id, uint32 stateSeq) } +status_t +RequestBuilder::Commit(uint64 offset, uint32 count) +{ + if (fProcedure != ProcCompound) + return B_BAD_VALUE; + if (fRequest == NULL) + return B_NO_MEMORY; + + fRequest->Stream().AddUInt(OpCommit); + fRequest->Stream().AddUHyper(offset); + fRequest->Stream().AddUInt(count); + + fOpCount++; + + return B_OK; +} + + status_t RequestBuilder::Create(FileType type, const char* name, AttrValue* attr, uint32 count, const char* path) @@ -729,7 +747,7 @@ RequestBuilder::Write(const uint32* id, uint32 stateSeq, const void* buffer, fRequest->Stream().AddUInt(id[1]); fRequest->Stream().AddUInt(id[2]); fRequest->Stream().AddUHyper(pos); - fRequest->Stream().AddInt(FILE_SYNC4); + fRequest->Stream().AddInt(UNSTABLE4); fRequest->Stream().AddOpaque(buffer, len); fOpCount++; diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h index 17800c9eca..b3b7998955 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h @@ -33,6 +33,7 @@ public: status_t Access(); status_t Close(uint32 seq, const uint32* id, uint32 stateSeq); + status_t Commit(uint64 offset, uint32 count); status_t Create(FileType type, const char* name, AttrValue* attr, uint32 count, const char* path = NULL); 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 15c0d00590..b1d0bd61e6 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -472,6 +472,7 @@ nfs4_free_cookie(fs_volume* volume, fs_vnode* vnode, void* _cookie) OpenFileCookie* cookie = reinterpret_cast(_cookie); file_cache_sync(inode->FileCache()); + inode->Commit(); inode->Close(cookie); delete cookie; From d4a75b9c9f2d3d77613ee8f0acb66cabf2238377 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Fri, 3 Aug 2012 19:12:22 +0200 Subject: [PATCH 150/252] nfs4: Use existing write cookie, do not send COMMIT if not necessary --- .../kernel/file_systems/nfs4/Inode.cpp | 4 +- src/add-ons/kernel/file_systems/nfs4/Inode.h | 19 +++++++++ .../kernel/file_systems/nfs4/InodeRegular.cpp | 5 +++ .../file_systems/nfs4/kernel_interface.cpp | 40 ++++++++----------- 4 files changed, 44 insertions(+), 24 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index 607df773de..68ed4e775d 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -24,7 +24,9 @@ Inode::Inode() : fAttrCacheExpire(0), fCache(NULL), - fFileCache(NULL) + fFileCache(NULL), + fWriteCookie(NULL), + fWriteDirty(false) { mutex_init(&fAttrCacheLock, NULL); } diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h b/src/add-ons/kernel/file_systems/nfs4/Inode.h index 692bfec298..30e0623d6e 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -31,6 +31,8 @@ public: inline FileSystem* GetFileSystem() const; inline void* FileCache(); + inline OpenFileCookie* WriteCookie(); + inline void SetWriteCookie(OpenFileCookie* cookie); status_t GetChangeInfo(uint64* change); @@ -116,6 +118,9 @@ protected: DirectoryCache* fCache; void* fFileCache; + OpenFileCookie* fWriteCookie; + + bool fWriteDirty; }; @@ -165,5 +170,19 @@ Inode::FileCache() } +inline OpenFileCookie* +Inode::WriteCookie() +{ + return fWriteCookie; +} + + +inline void +Inode::SetWriteCookie(OpenFileCookie* cookie) +{ + fWriteCookie = cookie; +} + + #endif // INODE_H diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp index c1f6bf86ab..df49273f99 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp @@ -384,6 +384,8 @@ Inode::Write(OpenFileCookie* cookie, off_t pos, const void* _buffer, uint64 fileSize; const char* buffer = reinterpret_cast(_buffer); + fWriteDirty = true; + while (size < *_length) { do { RPC::Server* serv = fFileSystem->Server(); @@ -460,6 +462,9 @@ Inode::Write(OpenFileCookie* cookie, off_t pos, const void* _buffer, status_t Inode::Commit() { + if (!fWriteDirty) + return B_OK; + do { RPC::Server* serv = fFileSystem->Server(); Request request(serv); 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 b1d0bd61e6..fd0307b282 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -221,6 +221,7 @@ nfs4_read_pages(fs_volume* _volume, fs_vnode* vnode, void* _cookie, off_t pos, OpenFileCookie* cookie = reinterpret_cast(_cookie); status_t result; + size_t totalRead = 0; bool eof = false; for (size_t i = 0; i < count && !eof; i++) { size_t bytesLeft = vecs[i].iov_len; @@ -232,12 +233,15 @@ nfs4_read_pages(fs_volume* _volume, fs_vnode* vnode, void* _cookie, off_t pos, if (result != B_OK) return result; + totalRead += bytesRead; pos += bytesRead; buffer += bytesRead; bytesLeft -= bytesRead; } while (bytesLeft > 0 && !eof); } + *_numBytes = totalRead; + return B_OK; } @@ -247,21 +251,12 @@ nfs4_write_pages(fs_volume* _volume, fs_vnode* vnode, void* _cookie, off_t pos, const iovec* vecs, size_t count, size_t* _numBytes) { Inode* inode = reinterpret_cast(vnode->private_node); - bool freeCookie = false; OpenFileCookie* cookie = reinterpret_cast(_cookie); if (cookie == NULL) { - cookie = new OpenFileCookie; + cookie = inode->WriteCookie(); if (cookie == NULL) - return B_NO_MEMORY; - - status_t result = inode->Open(O_WRONLY, cookie); - if (result != B_OK) { - delete cookie; - return result; - } - - freeCookie = true; + return B_BAD_VALUE; } status_t result; @@ -274,13 +269,8 @@ nfs4_write_pages(fs_volume* _volume, fs_vnode* vnode, void* _cookie, off_t pos, size_t bytesWritten = min_c(ioSize, bytesLeft); result = inode->Write(cookie, pos, buffer, &bytesWritten); - if (result != B_OK) { - if (freeCookie) { - inode->Close(cookie); - delete cookie; - } + if (result != B_OK) return result; - } bytesLeft -= bytesWritten; pos += bytesWritten; @@ -288,11 +278,6 @@ nfs4_write_pages(fs_volume* _volume, fs_vnode* vnode, void* _cookie, off_t pos, } while (bytesLeft > 0); } - if (freeCookie) { - inode->Close(cookie); - delete cookie; - } - return B_OK; } @@ -326,7 +311,11 @@ static status_t nfs4_fsync(fs_volume* volume, fs_vnode* vnode) { Inode* inode = reinterpret_cast(vnode->private_node); - return file_cache_sync(inode->FileCache()); + status_t result = file_cache_sync(inode->FileCache()); + if (result != B_OK) + return result; + + return inode->Commit(); } @@ -473,6 +462,10 @@ nfs4_free_cookie(fs_volume* volume, fs_vnode* vnode, void* _cookie) OpenFileCookie* cookie = reinterpret_cast(_cookie); file_cache_sync(inode->FileCache()); inode->Commit(); + + if (inode->WriteCookie() == cookie) + inode->SetWriteCookie(NULL); + inode->Close(cookie); delete cookie; @@ -520,6 +513,7 @@ nfs4_write(fs_volume* volume, fs_vnode* vnode, void* _cookie, off_t pos, if (result != B_OK) return result; + inode->SetWriteCookie(cookie); return file_cache_write(inode->FileCache(), cookie, pos, _buffer, length); } From 13a90e37953e4551e39dbe51feb6c1c92635c4d7 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Fri, 3 Aug 2012 19:37:32 +0200 Subject: [PATCH 151/252] nfs4: Revalidate cache before locks --- .../kernel/file_systems/nfs4/Inode.cpp | 47 ++++++++++++++++--- src/add-ons/kernel/file_systems/nfs4/Inode.h | 5 ++ .../file_systems/nfs4/kernel_interface.cpp | 8 +++- 3 files changed, 52 insertions(+), 8 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index 68ed4e775d..039da2d1c4 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -29,6 +29,7 @@ Inode::Inode() fWriteDirty(false) { mutex_init(&fAttrCacheLock, NULL); + mutex_init(&fFileCacheLock, NULL); } @@ -55,8 +56,8 @@ Inode::CreateInode(FileSystem* fs, const FileInfo &fi, Inode** _inode) req.PutFH(inode->fInfo.fHandle); - Attribute attr[] = { FATTR4_TYPE, FATTR4_SIZE, FATTR4_FSID, - FATTR4_FILEID }; + Attribute attr[] = { FATTR4_TYPE, FATTR4_CHANGE, FATTR4_SIZE, + FATTR4_FSID, FATTR4_FILEID }; req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); status_t result = request.Send(); @@ -73,14 +74,14 @@ Inode::CreateInode(FileSystem* fs, const FileInfo &fi, Inode** _inode) AttrValue* values; uint32 count; result = reply.GetAttr(&values, &count); - if (result != B_OK || count < 3) + if (result != B_OK || count < 4) return result; if (fi.fFileId == 0) { - if (count < 4 || values[3].fAttribute != FATTR4_FILEID) + if (count < 5 || values[4].fAttribute != FATTR4_FILEID) inode->fInfo.fFileId = fs->AllocFileId(); else - inode->fInfo.fFileId = values[3].fData.fValue64; + inode->fInfo.fFileId = values[4].fData.fValue64; } else inode->fInfo.fFileId = fi.fFileId; @@ -90,12 +91,15 @@ Inode::CreateInode(FileSystem* fs, const FileInfo &fi, Inode** _inode) if (inode->fType == NF4DIR) inode->fCache = new DirectoryCache(inode); + // FATTR4_CHANGE is mandatory + inode->fChange = values[1].fData.fValue64; + // FATTR4_SIZE is mandatory - size = values[1].fData.fValue64; + size = values[2].fData.fValue64; // FATTR4_FSID is mandatory FileSystemId* fsid = - reinterpret_cast(values[2].fData.fPointer); + reinterpret_cast(values[3].fData.fPointer); if (*fsid != fs->FsId()) { delete[] values; return B_ENTRY_NOT_FOUND; @@ -121,10 +125,39 @@ Inode::~Inode() file_cache_delete(fFileCache); delete fCache; + mutex_destroy(&fFileCacheLock); mutex_destroy(&fAttrCacheLock); } +status_t +Inode::RevalidateFileCache() +{ + uint64 change; + status_t result = GetChangeInfo(&change); + if (result != B_OK) + return result; + + MutexLocker _(fFileCacheLock); + if (change == fChange) + return B_OK; + + result = _UpdateAttrCache(true); + if (result != B_OK) + return result; + + file_cache_sync(fFileCache); + Commit(); + file_cache_delete(fFileCache); + + fFileCache = file_cache_create(fFileSystem->DevId(), ID(), + fAttrCache.st_size); + + change = fChange; + return B_OK; +} + + status_t Inode::GetChangeInfo(uint64* change) { diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h b/src/add-ons/kernel/file_systems/nfs4/Inode.h index 30e0623d6e..2385063bff 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -31,6 +31,8 @@ public: inline FileSystem* GetFileSystem() const; inline void* FileCache(); + status_t RevalidateFileCache(); + inline OpenFileCookie* WriteCookie(); inline void SetWriteCookie(OpenFileCookie* cookie); @@ -117,8 +119,11 @@ protected: FileSystem* fFileSystem; DirectoryCache* fCache; + + uint64 fChange; void* fFileCache; OpenFileCookie* fWriteCookie; + mutex fFileCacheLock; bool fWriteDirty; }; 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 fd0307b282..560a7a9355 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -429,7 +429,6 @@ nfs4_open(fs_volume* volume, fs_vnode* vnode, int openMode, void** _cookie) return B_NO_MEMORY; *_cookie = cookie; - status_t result = inode->Open(openMode, cookie); if (result != B_OK) delete cookie; @@ -605,6 +604,9 @@ nfs4_acquire_lock(fs_volume* volume, fs_vnode* vnode, void* _cookie, { Inode* inode = reinterpret_cast(vnode->private_node); OpenFileCookie* cookie = reinterpret_cast(_cookie); + + inode->RevalidateFileCache(); + return inode->AcquireLock(cookie, lock, wait); } @@ -619,6 +621,10 @@ nfs4_release_lock(fs_volume* volume, fs_vnode* vnode, void* _cookie, return B_OK; OpenFileCookie* cookie = reinterpret_cast(_cookie); + + file_cache_sync(inode->FileCache()); + inode->Commit(); + if (lock != NULL) return inode->ReleaseLock(cookie, lock); else From 0dbff361721c31a831a7adda62f198b6e6960b23 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Sat, 4 Aug 2012 00:00:25 +0200 Subject: [PATCH 152/252] nfs4: Move low level NFS4 code to Inode's base class --- .../kernel/file_systems/nfs4/Inode.cpp | 1134 ++++------------- src/add-ons/kernel/file_systems/nfs4/Inode.h | 60 +- .../kernel/file_systems/nfs4/InodeDir.cpp | 232 +--- .../kernel/file_systems/nfs4/InodeRegular.cpp | 433 +------ src/add-ons/kernel/file_systems/nfs4/Jamfile | 2 + .../kernel/file_systems/nfs4/NFS4Defs.h | 6 + .../kernel/file_systems/nfs4/NFS4Inode.cpp | 1016 +++++++++++++++ .../kernel/file_systems/nfs4/NFS4Inode.h | 78 ++ .../kernel/file_systems/nfs4/NFS4Object.cpp | 89 ++ .../kernel/file_systems/nfs4/NFS4Object.h | 29 + .../kernel/file_systems/nfs4/RootInode.cpp | 6 +- 11 files changed, 1573 insertions(+), 1512 deletions(-) create mode 100644 src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp create mode 100644 src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h create mode 100644 src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp create mode 100644 src/add-ons/kernel/file_systems/nfs4/NFS4Object.h diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index 039da2d1c4..53394cd8f5 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -66,7 +66,7 @@ Inode::CreateInode(FileSystem* fs, const FileInfo &fi, Inode** _inode) ReplyInterpreter& reply = request.Reply(); - if (inode->_HandleErrors(reply.NFS4Error(), serv)) + if (inode->HandleErrors(reply.NFS4Error(), serv)) continue; reply.PutFH(); @@ -142,7 +142,7 @@ Inode::RevalidateFileCache() if (change == fChange) return B_OK; - result = _UpdateAttrCache(true); + result = UpdateAttrCache(true); if (result != B_OK) return result; @@ -158,45 +158,6 @@ Inode::RevalidateFileCache() } -status_t -Inode::GetChangeInfo(uint64* change) -{ - do { - RPC::Server* serv = fFileSystem->Server(); - Request request(serv); - RequestBuilder& req = request.Builder(); - - req.PutFH(fInfo.fHandle); - - Attribute attr[] = { FATTR4_CHANGE }; - req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); - - status_t result = request.Send(); - if (result != B_OK) - return result; - - ReplyInterpreter& reply = request.Reply(); - - if (_HandleErrors(reply.NFS4Error(), serv)) - continue; - - reply.PutFH(); - - AttrValue* values; - uint32 count; - result = reply.GetAttr(&values, &count); - if (result != B_OK || count < 1) - return result; - - // FATTR4_CHANGE is mandatory - *change = values[0].fData.fValue64; - delete[] values; - - return B_OK; - } while (true); -} - - status_t Inode::LookUp(const char* name, ino_t* id) { @@ -208,472 +169,179 @@ Inode::LookUp(const char* name, ino_t* id) return B_OK; } - do { - RPC::Server* serv = fFileSystem->Server(); - Request request(serv); - RequestBuilder& req = request.Builder(); + uint64 change; + uint64 fileID; + FileHandle handle; + status_t result = NFS4Inode::LookUp(name, &change, &fileID, &handle); + if (result != B_OK) + return result; - req.PutFH(fInfo.fHandle); + *id = FileIdToInoT(fileID); - Attribute dirAttr[] = { FATTR4_CHANGE }; - req.GetAttr(dirAttr, sizeof(dirAttr) / sizeof(Attribute)); + result = ChildAdded(name, fileID, handle); + if (result != B_OK) + return result; - if (!strcmp(name, "..")) - req.LookUpUp(); - else - req.LookUp(name); + fFileSystem->Revalidator().Lock(); + if (fCache->Lock() != B_OK) { + fCache->ResetAndLock(); + fCache->SetChangeInfo(change); + } else { + fFileSystem->Revalidator().RemoveDirectory(fCache); + fCache->ValidateChangeInfo(change); + } - req.GetFH(); + fCache->AddEntry(name, *id); + fFileSystem->Revalidator().AddDirectory(fCache); + fCache->Unlock(); + fFileSystem->Revalidator().Unlock(); - Attribute attr[] = { FATTR4_FSID, 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 (_HandleErrors(reply.NFS4Error(), serv)) - continue; - - reply.PutFH(); - - AttrValue* values; - uint32 count; - result = reply.GetAttr(&values, &count); - if (result != B_OK) - return result; - - uint64 change = values[0].fData.fValue64; - delete[] values; - - if (!strcmp(name, "..")) - result = reply.LookUpUp(); - else - result = reply.LookUp(); - if (result != B_OK) - return result; - - FileHandle fh; - reply.GetFH(&fh); - - result = reply.GetAttr(&values, &count); - if (result != B_OK) - return result; - - // FATTR4_FSID is mandatory - FileSystemId* fsid = - reinterpret_cast(values[0].fData.fPointer); - if (*fsid != fFileSystem->FsId()) { - delete[] values; - return B_ENTRY_NOT_FOUND; - } - - uint64 fileId; - if (count < 2 || values[1].fAttribute != FATTR4_FILEID) - fileId = fFileSystem->AllocFileId(); - else - fileId = values[1].fData.fValue64; - delete[] values; - - *id = _FileIdToInoT(fileId); - - result = _ChildAdded(name, fileId, fh); - if (result != B_OK) - return result; - - fFileSystem->Revalidator().Lock(); - if (fCache->Lock() != B_OK) { - fCache->ResetAndLock(); - fCache->SetChangeInfo(change); - } else { - fFileSystem->Revalidator().RemoveDirectory(fCache); - fCache->ValidateChangeInfo(change); - } - - fCache->AddEntry(name, *id); - fFileSystem->Revalidator().AddDirectory(fCache); - fCache->Unlock(); - fFileSystem->Revalidator().Unlock(); - - return B_OK; - } while (true); + return B_OK; } status_t Inode::Link(Inode* dir, const char* name) { - do { - RPC::Server* serv = fFileSystem->Server(); - Request request(serv); - RequestBuilder& req = request.Builder(); + ChangeInfo changeInfo; + status_t result = NFS4Inode::Link(dir, name, &changeInfo); + if (result != B_OK) + return result; - req.PutFH(fInfo.fHandle); - req.SaveFH(); - req.PutFH(dir->fInfo.fHandle); - req.Link(name); + fFileSystem->Root()->MakeInfoInvalid(); - status_t result = request.Send(); - if (result != B_OK) - return result; + FileInfo fi = fInfo; + fi.fParent = dir->fInfo.fHandle; + free(const_cast(fi.fName)); + fi.fName = strdup(name); + if (fi.fName == NULL) + return B_NO_MEMORY; - ReplyInterpreter& reply = request.Reply(); + char* path = reinterpret_cast(malloc(strlen(name) + 2 + + strlen(fInfo.fPath))); + if (path == NULL) + return B_NO_MEMORY; - // FileHandle has expired - if (reply.NFS4Error() == NFS4ERR_FHEXPIRED) { - fInfo.UpdateFileHandles(fFileSystem); - dir->fInfo.UpdateFileHandles(dir->fFileSystem); - continue; - } + strcpy(path, dir->fInfo.fPath); + strcat(path, "/"); + strcat(path, name); + free(const_cast(fi.fPath)); + fi.fPath = path; - // filesystem has been moved - if (reply.NFS4Error() == NFS4ERR_MOVED) { - fFileSystem->Migrate(serv); - continue; - } + fFileSystem->InoIdMap()->AddEntry(fi, fInfo.fFileId); - reply.PutFH(); - reply.SaveFH(); - reply.PutFH(); + if (dir->fCache->Lock() == B_OK) { + if (changeInfo.fAtomic + && dir->fCache->ChangeInfo() == changeInfo.fBefore) { + dir->fCache->AddEntry(name, fInfo.fFileId, true); + dir->fCache->SetChangeInfo(changeInfo.fAfter); + } else if (dir->fCache->ChangeInfo() != changeInfo.fBefore) + dir->fCache->Trash(); + dir->fCache->Unlock(); + } - uint64 before, after; - bool atomic; - result = reply.Link(&before, &after, atomic); - if (result != B_OK) - return result; - - fFileSystem->Root()->MakeInfoInvalid(); - - FileInfo fi = fInfo; - fi.fParent = dir->fInfo.fHandle; - free(const_cast(fi.fName)); - fi.fName = strdup(name); - if (fi.fName == NULL) - return B_NO_MEMORY; - - char* path = reinterpret_cast(malloc(strlen(name) + 2 + - strlen(fInfo.fPath))); - if (path == NULL) - return B_NO_MEMORY; - - strcpy(path, dir->fInfo.fPath); - strcat(path, "/"); - strcat(path, name); - free(const_cast(fi.fPath)); - fi.fPath = path; - - fFileSystem->InoIdMap()->AddEntry(fi, fInfo.fFileId); - - if (dir->fCache->Lock() == B_OK) { - if (atomic && dir->fCache->ChangeInfo() == before) { - dir->fCache->AddEntry(name, fInfo.fFileId, true); - dir->fCache->SetChangeInfo(after); - } else if (dir->fCache->ChangeInfo() != before) - dir->fCache->Trash(); - dir->fCache->Unlock(); - } - - return B_OK; - } while (true); + return B_OK; } -// May cause problem similar to Rename (described below). When node's is has -// more than one hard link and we delete the name it stores for FileHandle -// restoration node will inocorectly become unavailable. status_t Inode::Remove(const char* name, FileType type) { - do { - RPC::Server* serv = fFileSystem->Server(); - Request request(serv); - RequestBuilder& req = request.Builder(); - - req.PutFH(fInfo.fHandle); - req.LookUp(name); - AttrValue attr; - attr.fAttribute = FATTR4_TYPE; - attr.fFreePointer = false; - attr.fData.fValue32 = NF4DIR; - if (type == NF4DIR) - req.Verify(&attr, 1); - else - req.Nverify(&attr, 1); - - req.PutFH(fInfo.fHandle); - req.Remove(name); - - status_t result = request.Send(); - if (result != B_OK) - return result; - - ReplyInterpreter& reply = request.Reply(); - - if (_HandleErrors(reply.NFS4Error(), serv)) - continue; - - reply.PutFH(); - result = reply.LookUp(); - if (result != B_OK) - return result; - - if (type == NF4DIR) - result = reply.Verify(); - else - result = reply.Nverify(); - - if (result == NFS4ERR_SAME && type != NF4DIR) - return B_IS_A_DIRECTORY; - if (result == NFS4ERR_NOT_SAME && type == NF4DIR) - return B_NOT_A_DIRECTORY; - if (result != B_OK) - return result; - - reply.PutFH(); - - uint64 before, after; - bool atomic; - result = reply.Remove(&before, &after, atomic); - - if (fCache->Lock() == B_OK) { - if (atomic && fCache->ChangeInfo() == before) { - fCache->RemoveEntry(name); - fCache->SetChangeInfo(after); - } else if (fCache->ChangeInfo() != before) - fCache->Trash(); - fCache->Unlock(); - } - - fFileSystem->Root()->MakeInfoInvalid(); - + ChangeInfo changeInfo; + status_t result = NFS4Inode::RemoveObject(name, type, &changeInfo); + if (result != B_OK) return result; - } while (true); + + if (fCache->Lock() == B_OK) { + if (changeInfo.fAtomic + && fCache->ChangeInfo() == changeInfo.fBefore) { + fCache->RemoveEntry(name); + fCache->SetChangeInfo(changeInfo.fAfter); + } else if (fCache->ChangeInfo() != changeInfo.fBefore) + fCache->Trash(); + fCache->Unlock(); + } + + fFileSystem->Root()->MakeInfoInvalid(); + + return B_OK; } -// Rename may cause some problems if FileHandles are volatile and local Inode -// object exists for renamed node. It's stored filename will become invalid -// and, consequnetly, FileHandle restoration will fail. Probably, it will -// be much easier to solve this problem if more metadata is cached. status_t Inode::Rename(Inode* from, Inode* to, const char* fromName, const char* toName) { if (from->fFileSystem != to->fFileSystem) return B_DONT_DO_THAT; - do { - RPC::Server* serv = from->fFileSystem->Server(); - Request request(serv); - RequestBuilder& req = request.Builder(); + ChangeInfo fromChange, toChange; + uint64 fileID; + status_t result = NFS4Inode::Rename(from, to, fromName, toName, &fromChange, + &toChange, &fileID); + if (result != B_OK) + return result; - req.PutFH(from->fInfo.fHandle); - req.SaveFH(); - req.PutFH(to->fInfo.fHandle); - req.Rename(fromName, toName); + from->fFileSystem->Root()->MakeInfoInvalid(); - Attribute attr[] = { FATTR4_FILEID }; - req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); - req.LookUp(toName); + if (from->fCache->Lock() == B_OK) { + if (fromChange.fAtomic + && from->fCache->ChangeInfo() == fromChange.fBefore) { + from->fCache->RemoveEntry(fromName); + from->fCache->SetChangeInfo(fromChange.fAfter); + } else if (from->fCache->ChangeInfo() != fromChange.fBefore) + from->fCache->Trash(); + from->fCache->Unlock(); + } - status_t result = request.Send(); - if (result != B_OK) - return result; + if (to->fCache->Lock() == B_OK) { + if (toChange.fAtomic + && to->fCache->ChangeInfo() == toChange.fBefore) { + to->fCache->AddEntry(toName, fileID, true); + to->fCache->SetChangeInfo(toChange.fAfter); + } else if (to->fCache->ChangeInfo() != toChange.fBefore) + to->fCache->Trash(); + to->fCache->Unlock(); + } - ReplyInterpreter& reply = request.Reply(); - - // FileHandle has expired - if (reply.NFS4Error() == NFS4ERR_FHEXPIRED) { - from->fInfo.UpdateFileHandles(from->fFileSystem); - to->fInfo.UpdateFileHandles(to->fFileSystem); - continue; - } - - // filesystem has been moved - if (reply.NFS4Error() == NFS4ERR_MOVED) { - from->fFileSystem->Migrate(serv); - continue; - } - - reply.PutFH(); - reply.SaveFH(); - reply.PutFH(); - - uint64 fromBefore, fromAfter, toBefore, toAfter; - bool fromAtomic, toAtomic; - result = reply.Rename(&fromBefore, &fromAfter, fromAtomic, &toBefore, - &toAfter, toAtomic); - if (result != B_OK) - return result; - - result = reply.LookUp(); - 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 = from->fFileSystem->AllocFileId(); - else - fileID = values[1].fData.fValue64; - - from->fFileSystem->Root()->MakeInfoInvalid(); - - if (from->fCache->Lock() == B_OK) { - if (fromAtomic && from->fCache->ChangeInfo() == fromBefore) { - from->fCache->RemoveEntry(fromName); - from->fCache->SetChangeInfo(fromAfter); - } else if (from->fCache->ChangeInfo() != fromBefore) - from->fCache->Trash(); - from->fCache->Unlock(); - } - - if (to->fCache->Lock() == B_OK) { - if (toAtomic && to->fCache->ChangeInfo() == toBefore) { - to->fCache->AddEntry(toName, fileID, true); - to->fCache->SetChangeInfo(toAfter); - } else if (to->fCache->ChangeInfo() != toBefore) - to->fCache->Trash(); - to->fCache->Unlock(); - } - - return B_OK; - } while (true); + return B_OK; } status_t Inode::CreateLink(const char* name, const char* path, int mode) { - bool badOwner = false; - - 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(NF4LNK, name, cattr, i, path); - - 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; - reply.GetFH(&handle); - - 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; - - fFileSystem->Root()->MakeInfoInvalid(); - - 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); + return CreateObject(name, path, mode, NF4LNK); } status_t -Inode::ReadLink(void* buffer, size_t* length) +Inode::CreateObject(const char* name, const char* path, int mode, FileType type) { - if (fType != NF4LNK) - return B_BAD_VALUE; + ChangeInfo changeInfo; + uint64 fileID; + FileHandle handle; - do { - RPC::Server* serv = fFileSystem->Server(); - Request request(serv); - RequestBuilder& req = request.Builder(); + status_t result = NFS4Inode::CreateObject(name, path, mode, type, &changeInfo, + &fileID, &handle); + if (result != B_OK) + return B_OK; - req.PutFH(fInfo.fHandle); - req.ReadLink(); + fFileSystem->Root()->MakeInfoInvalid(); - status_t result = request.Send(); - if (result != B_OK) - return result; + result = ChildAdded(name, fileID, handle); + if (result != B_OK) + return B_OK; - ReplyInterpreter& reply = request.Reply(); + if (fCache->Lock() == B_OK) { + if (changeInfo.fAtomic && fCache->ChangeInfo() == changeInfo.fBefore) { + fCache->AddEntry(name, fileID, true); + fCache->SetChangeInfo(changeInfo.fAfter); + } else if (fCache->ChangeInfo() != changeInfo.fBefore) + fCache->Trash(); + fCache->Unlock(); + } - if (_HandleErrors(reply.NFS4Error(), serv)) - continue; - - reply.PutFH(); - - uint32 size; - result = reply.ReadLink(buffer, &size, *length); - *length = static_cast(size); - - return result; - } while (true); + return B_OK; } @@ -682,69 +350,22 @@ Inode::Access(int mode) { int acc = 0; - if (fFileSystem->IsAttrSupported(FATTR4_MODE)) { - status_t result = _UpdateAttrCache(); - if (result != B_OK) - return result; + uint32 allowed; + status_t result = NFS4Inode::Access(&allowed); + if (result != B_OK) + return result; - // Root squashing and owner mapping problems may make this function - // return false values. However, since due to race condition it can - // not be used for anything critical, it is not a serius problem. + if ((allowed & ACCESS4_READ) != 0) + acc |= R_OK; - mode_t nodeMode = fAttrCache.st_mode; - uint8 userMode = (nodeMode & S_IRWXU) >> 6; - uint8 groupMode = (nodeMode & S_IRWXG) >> 3; - uint8 otherMode = (nodeMode & S_IRWXO); + if ((allowed & ACCESS4_LOOKUP) != 0) + acc |= X_OK | R_OK; - uid_t uid = geteuid(); - if (uid == 0) - acc = userMode | groupMode | otherMode | R_OK | W_OK; - else if (uid == fAttrCache.st_uid) - acc = userMode; - else if (getegid() == fAttrCache.st_gid) - acc = groupMode; - else - acc = otherMode; - } else { - do { - RPC::Server* serv = fFileSystem->Server(); - Request request(serv); - RequestBuilder& req = request.Builder(); + if ((allowed & ACCESS4_EXECUTE) != 0) + acc |= X_OK; - req.PutFH(fInfo.fHandle); - req.Access(); - - status_t result = request.Send(); - 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) != 0) - acc |= R_OK; - - if (fType == NF4DIR && (allowed & ACCESS4_LOOKUP) != 0) - acc |= X_OK | R_OK; - - if (fType != NF4DIR && (allowed & ACCESS4_EXECUTE) != 0) - acc |= X_OK; - - if ((allowed & ACCESS4_MODIFY) != 0) - acc |= W_OK; - - break; - } while (true); - } + if ((allowed & ACCESS4_MODIFY) != 0) + acc |= W_OK; if ((mode & acc) != mode) return B_NOT_ALLOWED; @@ -756,7 +377,7 @@ Inode::Access(int mode) status_t Inode::Stat(struct stat* st) { - status_t result = _UpdateAttrCache(); + status_t result = UpdateAttrCache(); if (result != B_OK) return result; @@ -776,7 +397,7 @@ Inode::Stat(struct stat* st) status_t -Inode::_UpdateAttrCache(bool force) +Inode::UpdateAttrCache(bool force) { if (!force && fAttrCacheExpire > time(NULL)) return B_OK; @@ -786,135 +407,85 @@ Inode::_UpdateAttrCache(bool force) if (fAttrCacheExpire > time(NULL)) return B_OK; - do { - RPC::Server* serv = fFileSystem->Server(); - Request request(serv); - RequestBuilder& req = request.Builder(); - - req.PutFH(fInfo.fHandle); - - Attribute attr[] = { FATTR4_SIZE, FATTR4_MODE, FATTR4_NUMLINKS, - FATTR4_OWNER, FATTR4_OWNER_GROUP, - FATTR4_TIME_ACCESS, FATTR4_TIME_CREATE, - FATTR4_TIME_METADATA, FATTR4_TIME_MODIFY }; - req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); - - status_t result = request.Send(); - if (result != B_OK) - return result; - - ReplyInterpreter& reply = request.Reply(); - - if (_HandleErrors(reply.NFS4Error(), serv)) - continue; - - reply.PutFH(); - - AttrValue* values; - uint32 count; - result = reply.GetAttr(&values, &count); - if (result != B_OK) - return result; - - // FATTR4_SIZE is mandatory - if (count < 1 || values[0].fAttribute != FATTR4_SIZE) { - delete[] values; - return B_BAD_VALUE; - } - fAttrCache.st_size = values[0].fData.fValue64; - - uint32 next = 1; - fAttrCache.st_mode = Type(); - if (count >= next && values[next].fAttribute == FATTR4_MODE) { - fAttrCache.st_mode |= values[next].fData.fValue32; - next++; - } else { - // Try to guess using ACCESS request - request.Reset(); - request.Builder().PutFH(fInfo.fHandle); - request.Builder().Access(); - result = request.Send(); - if (result != B_OK) - return result; - request.Reply().PutFH(); - uint32 prvl; - result = request.Reply().Access(NULL, &prvl); - if (result != B_OK) - return result; - - if ((prvl & ACCESS4_READ) != 0) - fAttrCache.st_mode |= S_IRUSR | S_IRGRP | S_IROTH; - - if ((prvl & ACCESS4_MODIFY) != 0) - fAttrCache.st_mode |= S_IWUSR | S_IWGRP | S_IWOTH; - - if (fType == NF4DIR && (prvl & ACCESS4_LOOKUP) != 0) - fAttrCache.st_mode |= S_IXUSR | S_IXGRP | S_IXOTH; - - if (fType != NF4DIR && (prvl & ACCESS4_EXECUTE) != 0) - fAttrCache.st_mode |= S_IXUSR | S_IXGRP | S_IXOTH; - } - - if (count >= next && values[next].fAttribute == FATTR4_NUMLINKS) { - fAttrCache.st_nlink = values[next].fData.fValue32; - next++; - } else - fAttrCache.st_nlink = 1; - - if (count >= next && values[next].fAttribute == FATTR4_OWNER) { - char* owner = reinterpret_cast(values[next].fData.fPointer); - if (owner != NULL && isdigit(owner[0])) - fAttrCache.st_uid = atoi(owner); - else - fAttrCache.st_uid = gIdMapper->GetUserId(owner); - next++; - } else - fAttrCache.st_uid = 0; - - if (count >= next && values[next].fAttribute == FATTR4_OWNER_GROUP) { - char* group = reinterpret_cast(values[next].fData.fPointer); - if (group != NULL && isdigit(group[0])) - fAttrCache.st_gid = atoi(group); - else - fAttrCache.st_gid = gIdMapper->GetGroupId(group); - next++; - } else - fAttrCache.st_gid = 0; - - if (count >= next && values[next].fAttribute == FATTR4_TIME_ACCESS) { - memcpy(&fAttrCache.st_atim, values[next].fData.fPointer, - sizeof(timespec)); - next++; - } else - memset(&fAttrCache.st_atim, 0, sizeof(timespec)); - - if (count >= next && values[next].fAttribute == FATTR4_TIME_CREATE) { - memcpy(&fAttrCache.st_crtim, values[next].fData.fPointer, - sizeof(timespec)); - next++; - } else - memset(&fAttrCache.st_crtim, 0, sizeof(timespec)); - - if (count >= next && values[next].fAttribute == FATTR4_TIME_METADATA) { - memcpy(&fAttrCache.st_ctim, values[next].fData.fPointer, - sizeof(timespec)); - next++; - } else - memset(&fAttrCache.st_ctim, 0, sizeof(timespec)); - - if (count >= next && values[next].fAttribute == FATTR4_TIME_MODIFY) { - memcpy(&fAttrCache.st_mtim, values[next].fData.fPointer, - sizeof(timespec)); - next++; - } else - memset(&fAttrCache.st_mtim, 0, sizeof(timespec)); + AttrValue* values; + uint32 count; + status_t result = GetStat(&values, &count); + if (result != B_OK) + return result; + // FATTR4_SIZE is mandatory + if (count < 1 || values[0].fAttribute != FATTR4_SIZE) { delete[] values; + return B_BAD_VALUE; + } + fAttrCache.st_size = values[0].fData.fValue64; - fAttrCacheExpire = time(NULL) + kAttrCacheExpirationTime; + uint32 next = 1; + fAttrCache.st_mode = Type(); + if (count >= next && values[next].fAttribute == FATTR4_MODE) { + fAttrCache.st_mode |= values[next].fData.fValue32; + next++; + } else + fAttrCache.st_mode = 777; - return B_OK; - } while (true); + if (count >= next && values[next].fAttribute == FATTR4_NUMLINKS) { + fAttrCache.st_nlink = values[next].fData.fValue32; + next++; + } else + fAttrCache.st_nlink = 1; + + if (count >= next && values[next].fAttribute == FATTR4_OWNER) { + char* owner = reinterpret_cast(values[next].fData.fPointer); + if (owner != NULL && isdigit(owner[0])) + fAttrCache.st_uid = atoi(owner); + else + fAttrCache.st_uid = gIdMapper->GetUserId(owner); + next++; + } else + fAttrCache.st_uid = 0; + + if (count >= next && values[next].fAttribute == FATTR4_OWNER_GROUP) { + char* group = reinterpret_cast(values[next].fData.fPointer); + if (group != NULL && isdigit(group[0])) + fAttrCache.st_gid = atoi(group); + else + fAttrCache.st_gid = gIdMapper->GetGroupId(group); + next++; + } else + fAttrCache.st_gid = 0; + + if (count >= next && values[next].fAttribute == FATTR4_TIME_ACCESS) { + memcpy(&fAttrCache.st_atim, values[next].fData.fPointer, + sizeof(timespec)); + next++; + } else + memset(&fAttrCache.st_atim, 0, sizeof(timespec)); + + if (count >= next && values[next].fAttribute == FATTR4_TIME_CREATE) { + memcpy(&fAttrCache.st_crtim, values[next].fData.fPointer, + sizeof(timespec)); + next++; + } else + memset(&fAttrCache.st_crtim, 0, sizeof(timespec)); + + if (count >= next && values[next].fAttribute == FATTR4_TIME_METADATA) { + memcpy(&fAttrCache.st_ctim, values[next].fData.fPointer, + sizeof(timespec)); + next++; + } else + memset(&fAttrCache.st_ctim, 0, sizeof(timespec)); + + if (count >= next && values[next].fAttribute == FATTR4_TIME_MODIFY) { + memcpy(&fAttrCache.st_mtim, values[next].fData.fPointer, + sizeof(timespec)); + next++; + } else + memset(&fAttrCache.st_mtim, 0, sizeof(timespec)); + delete[] values; + + fAttrCacheExpire = time(NULL) + kAttrCacheExpirationTime; + + return B_OK; } @@ -981,51 +552,21 @@ Inode::WriteStat(const struct stat* st, uint32 mask) i++; } - do { - RPC::Server* serv = fFileSystem->Server(); - Request request(serv); - RequestBuilder& req = request.Builder(); + result = NFS4Inode::WriteStat(cookie, attr, i); - req.PutFH(fInfo.fHandle); - if ((mask & B_STAT_SIZE) != 0) - req.SetAttr(cookie->fStateId, cookie->fStateSeq, attr, i); - else - req.SetAttr(NULL, 0, attr, i); + if ((mask & B_STAT_SIZE) != 0) { + Close(cookie); + delete cookie; + } - status_t result = request.Send(); - if (result != B_OK) { - Close(cookie); - delete cookie; - return result; - } + UpdateAttrCache(true); - ReplyInterpreter& reply = request.Reply(); - - if (_HandleErrors(reply.NFS4Error(), serv)) - continue; - - reply.PutFH(); - result = reply.SetAttr(); - - if ((mask & B_STAT_SIZE) != 0) { - Close(cookie); - delete cookie; - } - - if (result != B_OK) - return result; - - break; - } while (true); - - _UpdateAttrCache(true); - - return B_OK; + return result; } inline status_t -Inode::_CheckLockType(short ltype, uint32 mode) +Inode::CheckLockType(short ltype, uint32 mode) { switch (ltype) { case F_UNLCK: @@ -1046,62 +587,43 @@ Inode::_CheckLockType(short ltype, uint32 mode) } } - status_t Inode::TestLock(OpenFileCookie* cookie, struct flock* lock) { if (lock->l_type == F_UNLCK) return B_OK; - status_t result = _CheckLockType(lock->l_type, cookie->fMode); + status_t result = CheckLockType(lock->l_type, cookie->fMode); if (result != B_OK) return result; - do { - RPC::Server* serv = fFileSystem->Server(); - Request request(serv); - RequestBuilder& req = request.Builder(); - - req.PutFH(fInfo.fHandle); - req.LockT(sGetLockType(lock->l_type, false), lock->l_start, - lock->l_len, cookie); - - status_t result = request.Send(); - if (result != B_OK) - return result; - - ReplyInterpreter &reply = request.Reply(); - if (_HandleErrors(reply.NFS4Error(), serv, cookie)) - continue; - - reply.PutFH(); - LockType ltype; - uint64 pos, len; - result = reply.LockT(&pos, &len, <ype); - if (reply.NFS4Error() == NFS4ERR_DENIED) { - lock->l_type = sLockTypeToHaiku(ltype); - lock->l_start = static_cast(pos); - if (len >= OFF_MAX) - lock->l_len = OFF_MAX; - else - lock->l_len = static_cast(len); - - result = B_OK; - } else if (reply.NFS4Error() == NFS4_OK) - lock->l_type = F_UNLCK; + LockType ltype = sGetLockType(lock->l_type, false); + uint64 position = lock->l_start; + uint64 length = lock->l_len; + bool conflict; + result = NFS4Inode::TestLock(cookie, <ype, &position, &length, conflict); + if (result != B_OK) return result; - } while (true); + + if (conflict) { + lock->l_type = sLockTypeToHaiku(ltype); + lock->l_start = static_cast(position); + if (length >= OFF_MAX) + lock->l_len = OFF_MAX; + else + lock->l_len = static_cast(length); + } else + lock->l_type = F_UNLCK; return B_OK; } - status_t Inode::AcquireLock(OpenFileCookie* cookie, const struct flock* lock, bool wait) { - status_t result = _CheckLockType(lock->l_type, cookie->fMode); + status_t result = CheckLockType(lock->l_type, cookie->fMode); if (result != B_OK) return result; @@ -1125,42 +647,9 @@ Inode::AcquireLock(OpenFileCookie* cookie, const struct flock* lock, linfo->fLength = lock->l_len; linfo->fType = sGetLockType(lock->l_type, wait); - do { - MutexLocker ownerLocker(linfo->fOwner->fLock); - - RPC::Server* serv = fFileSystem->Server(); - Request request(serv); - RequestBuilder& req = request.Builder(); - - req.PutFH(fInfo.fHandle); - req.Lock(cookie, linfo); - - status_t result = request.Send(); - if (result != B_OK) { - cookie->DeleteLock(linfo); - return result; - } - - ReplyInterpreter &reply = request.Reply(); - - reply.PutFH(); - result = reply.Lock(linfo); - - ownerLocker.Unlock(); - if (wait && reply.NFS4Error() == NFS4ERR_DENIED) { - snooze_etc(sSecToBigTime(5), B_SYSTEM_TIMEBASE, - B_RELATIVE_TIMEOUT); - continue; - } - if (_HandleErrors(reply.NFS4Error(), serv, cookie)) - continue; - - if (result != B_OK) { - cookie->DeleteLock(linfo); - return result; - } - break; - } while (true); + result = NFS4Inode::AcquireLock(cookie, linfo, wait); + if (result != B_OK) + return result; MutexLocker _(cookie->fLocksLock); cookie->AddLock(linfo); @@ -1194,38 +683,9 @@ Inode::ReleaseLock(OpenFileCookie* cookie, const struct flock* lock) if (linfo == NULL) return B_BAD_VALUE; - do { - MutexLocker ownerLocker(linfo->fOwner->fLock); - - RPC::Server* serv = fFileSystem->Server(); - Request request(serv); - RequestBuilder& req = request.Builder(); - - req.PutFH(fInfo.fHandle); - req.LockU(linfo); - - status_t result = request.Send(); - if (result != B_OK) { - cookie->DeleteLock(linfo); - return result; - } - - ReplyInterpreter &reply = request.Reply(); - - reply.PutFH(); - result = reply.LockU(linfo); - - ownerLocker.Unlock(); - if (_HandleErrors(reply.NFS4Error(), serv, cookie)) - continue; - - if (result != B_OK) { - cookie->DeleteLock(linfo); - return result; - } - - break; - } while (true); + status_t result = NFS4Inode::ReleaseLock(cookie, linfo); + if (result != B_OK) + return result; cookie->DeleteLock(linfo); @@ -1239,32 +699,8 @@ Inode::ReleaseAllLocks(OpenFileCookie* cookie) MutexLocker _(cookie->fLocksLock); LockInfo* linfo = cookie->fLocks; while (linfo != NULL) { - do { - MutexLocker ownerLocker(linfo->fOwner->fLock); - - RPC::Server* serv = fFileSystem->Server(); - Request request(serv); - RequestBuilder& req = request.Builder(); - - req.PutFH(fInfo.fHandle); - req.LockU(linfo); - - status_t result = request.Send(); - if (result != B_OK) - break; - - ReplyInterpreter& reply = request.Reply(); - - reply.PutFH(); - reply.LockU(linfo); - - ownerLocker.Unlock(); - if (_HandleErrors(reply.NFS4Error(), serv, cookie)) - continue; - - break; - } while (true); - + MutexLocker ownerLocker(linfo->fOwner->fLock); + NFS4Inode::ReleaseLock(cookie, linfo); cookie->RemoveLock(linfo, NULL); cookie->DeleteLock(linfo); @@ -1275,86 +711,8 @@ Inode::ReleaseAllLocks(OpenFileCookie* cookie) } -bool -Inode::_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; - } -} - - status_t -Inode::_ChildAdded(const char* name, uint64 fileID, +Inode::ChildAdded(const char* name, uint64 fileID, const FileHandle& fileHandle) { fFileSystem->Root()->MakeInfoInvalid(); @@ -1377,6 +735,6 @@ Inode::_ChildAdded(const char* name, uint64 fileID, strcat(path, name); fi.fPath = path; - return fFileSystem->InoIdMap()->AddEntry(fi, _FileIdToInoT(fileID)); + return fFileSystem->InoIdMap()->AddEntry(fi, FileIdToInoT(fileID)); } diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h b/src/add-ons/kernel/file_systems/nfs4/Inode.h index 2385063bff..0581251f8f 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -9,17 +9,10 @@ #define INODE_H -#include - -#include - -#include "Cookie.h" -#include "FileSystem.h" -#include "NFS4Defs.h" -#include "ReplyInterpreter.h" +#include "NFS4Inode.h" -class Inode { +class Inode : public NFS4Inode { public: static status_t CreateInode(FileSystem* fs, const FileInfo& fi, Inode** inode); @@ -36,22 +29,23 @@ public: inline OpenFileCookie* WriteCookie(); 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 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, int mode); - status_t ReadLink(void* buffer, size_t* length); status_t Link(Inode* dir, const char* name); status_t Remove(const char* name, FileType type); static status_t Rename(Inode* from, Inode* to, const char* fromName, const char* toName); - status_t Access(int mode); status_t Stat(struct stat* st); status_t WriteStat(const struct stat* st, uint32 mask); @@ -77,46 +71,32 @@ public: const struct flock* lock); status_t ReleaseAllLocks(OpenFileCookie* cookie); - protected: Inode(); - bool _HandleErrors(uint32 nfs4Error, - 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, + status_t ReadDirUp(struct dirent* de, uint32 pos, 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, uint64* _change); - status_t _ChildAdded(const char* name, uint64 fileID, + status_t ChildAdded(const char* name, uint64 fileID, 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; mutex fAttrCacheLock; time_t fAttrCacheExpire; static const time_t kAttrCacheExpirationTime = 60; - status_t _UpdateAttrCache(bool force = false); - - uint32 fType; - - FileInfo fInfo; - FileSystem* fFileSystem; DirectoryCache* fCache; @@ -130,7 +110,7 @@ protected: inline ino_t -Inode::_FileIdToInoT(uint64 fileid) +Inode::FileIdToInoT(uint64 fileid) { if (sizeof(ino_t) >= sizeof(uint64)) return fileid; @@ -143,7 +123,7 @@ Inode::_FileIdToInoT(uint64 fileid) inline ino_t Inode::ID() const { - return _FileIdToInoT(fInfo.fFileId); + return FileIdToInoT(fInfo.fFileId); } diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp b/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp index e12ab4c97e..c303678c9b 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp @@ -20,95 +20,7 @@ status_t Inode::CreateDir(const char* name, int mode) { - bool badOwner = false; - - 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); + return CreateObject(name, NULL, mode, NF4DIR); } @@ -118,116 +30,22 @@ Inode::OpenDir(OpenDirCookie* cookie) if (fType != NF4DIR) return B_NOT_A_DIRECTORY; - do { - RPC::Server* serv = fFileSystem->Server(); - Request request(serv); - RequestBuilder& req = request.Builder(); + status_t result = Access(R_OK); + if (result != B_OK) + return result; - req.PutFH(fInfo.fHandle); - req.Access(); + cookie->fFileSystem = fFileSystem; + cookie->fSpecial = 0; + cookie->fSnapshot = NULL; + cookie->fCurrent = NULL; + cookie->fEOF = false; - status_t result = request.Send(); - 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); + return B_OK; } status_t -Inode::_ReadDirOnce(DirEntry** dirents, uint32* count, OpenDirCookie* cookie, - 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, +Inode::FillDirEntry(struct dirent* de, ino_t id, const char* name, uint32 pos, uint32 size) { uint32 nameSize = strlen(name); @@ -249,7 +67,7 @@ Inode::_FillDirEntry(struct dirent* de, ino_t id, const char* name, uint32 pos, status_t -Inode::_ReadDirUp(struct dirent* de, uint32 pos, uint32 size) +Inode::ReadDirUp(struct dirent* de, uint32 pos, uint32 size) { do { RPC::Server* serv = fFileSystem->Server(); @@ -271,7 +89,7 @@ Inode::_ReadDirUp(struct dirent* de, uint32 pos, uint32 size) ReplyInterpreter& reply = request.Reply(); - if (_HandleErrors(reply.NFS4Error(), serv)) + if (HandleErrors(reply.NFS4Error(), serv)) continue; reply.PutFH(); @@ -295,13 +113,13 @@ Inode::_ReadDirUp(struct dirent* de, uint32 pos, uint32 size) } else fileId = fFileSystem->AllocFileId(); - return _FillDirEntry(de, _FileIdToInoT(fileId), "..", pos, size); + return FillDirEntry(de, FileIdToInoT(fileId), "..", pos, size); } while (true); } status_t -Inode::_GetDirSnapshot(DirectoryCacheSnapshot** _snapshot, +Inode::GetDirSnapshot(DirectoryCacheSnapshot** _snapshot, OpenDirCookie* cookie, uint64* _change) { DirectoryCacheSnapshot* snapshot = new DirectoryCacheSnapshot; @@ -317,7 +135,7 @@ Inode::_GetDirSnapshot(DirectoryCacheSnapshot** _snapshot, uint32 count; DirEntry* dirents; - status_t result = _ReadDirOnce(&dirents, &count, cookie, &eof, &change, + status_t result = ReadDirOnce(&dirents, &count, cookie, &eof, &change, &dirCookie, &dirCookieVerf); if (result != B_OK) { delete snapshot; @@ -335,9 +153,9 @@ Inode::_GetDirSnapshot(DirectoryCacheSnapshot** _snapshot, ino_t id; if (dirents[i].fAttrCount == 2) - id = _FileIdToInoT(dirents[i].fAttrs[1].fData.fValue64); + id = FileIdToInoT(dirents[i].fAttrs[1].fData.fValue64); else - id = _FileIdToInoT(fFileSystem->AllocFileId()); + id = FileIdToInoT(fFileSystem->AllocFileId()); NameCacheEntry* entry = new NameCacheEntry(dirents[i].fName, id); if (entry == NULL || entry->fName == NULL) { @@ -381,7 +199,7 @@ Inode::ReadDir(void* _buffer, uint32 size, uint32* _count, cookie->fSnapshot = fCache->GetSnapshot(); if (cookie->fSnapshot == NULL) { uint64 change; - result = _GetDirSnapshot(&cookie->fSnapshot, cookie, &change); + result = GetDirSnapshot(&cookie->fSnapshot, cookie, &change); if (result != B_OK) { fCache->Unlock(); fFileSystem->Revalidator().Unlock(); @@ -405,7 +223,7 @@ Inode::ReadDir(void* _buffer, uint32 size, uint32* _count, struct dirent* de = reinterpret_cast(buffer + pos); status_t result; - result = _FillDirEntry(de, fInfo.fFileId, ".", pos, size); + result = FillDirEntry(de, fInfo.fFileId, ".", pos, size); if (result == B_BUFFER_OVERFLOW) overflow = true; @@ -422,9 +240,11 @@ Inode::ReadDir(void* _buffer, uint32 size, uint32* _count, status_t result; if (strcmp(fInfo.fName, "/")) - result = _ReadDirUp(de, pos, size); - else - result = _FillDirEntry(de, _FileIdToInoT(fInfo.fFileId), "..", pos, size); + result = ReadDirUp(de, pos, size); + else { + result = FillDirEntry(de, FileIdToInoT(fInfo.fFileId), "..", pos, + size); + } if (result == B_BUFFER_OVERFLOW) overflow = true; @@ -452,7 +272,7 @@ Inode::ReadDir(void* _buffer, uint32 size, uint32* _count, break; } - if (_FillDirEntry(de, cookie->fCurrent->fNode, cookie->fCurrent->fName, + if (FillDirEntry(de, cookie->fCurrent->fNode, cookie->fCurrent->fName, pos, size) == B_BUFFER_OVERFLOW) { overflow = true; break; diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp index df49273f99..d9da7c2b9b 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp @@ -19,182 +19,55 @@ #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 Inode::Create(const char* name, int mode, int perms, OpenFileCookie* cookie, ino_t* id) { - bool confirm; - status_t result; - cookie->fMode = mode; cookie->fSequence = 0; cookie->fLocks = NULL; - bool badOwner = false; - FileHandle fh; - do { - cookie->fClientId = fFileSystem->NFSServer()->ClientId(); + uint64 fileID; + FileHandle handle; + ChangeInfo changeInfo; + status_t result = CreateFile(name, mode, perms, cookie, &changeInfo, + &fileID, &handle); + if (result != B_OK) + return result; - RPC::Server* serv = fFileSystem->Server(); - Request request(serv); - RequestBuilder& req = request.Builder(); + *id = FileIdToInoT(fileID); - 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(malloc(strlen(name) + 2 + + strlen(fInfo.fPath))); + strcpy(path, fInfo.fPath); + strcat(path, "/"); + strcat(path, name); + fi.fPath = path; - AttrValue cattr[4]; - 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++; + fFileSystem->InoIdMap()->AddEntry(fi, *id); - if (!badOwner && fFileSystem->IsAttrSupported(FATTR4_OWNER)) { - cattr[i].fAttribute = FATTR4_OWNER; - cattr[i].fFreePointer = true; - cattr[i].fData.fPointer = gIdMapper->GetOwner(getuid()); - i++; - } + if (fCache->Lock() == B_OK) { + if (changeInfo.fAtomic + && fCache->ChangeInfo() == changeInfo.fBefore) { + fCache->AddEntry(name, fileID, true); + fCache->SetChangeInfo(changeInfo.fAfter); + } else if (fCache->ChangeInfo() != changeInfo.fBefore) + fCache->Trash(); + fCache->Unlock(); + } - 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.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(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); + cookie->fFileSystem = fFileSystem; + cookie->fInfo = fi; fFileSystem->AddOpenFile(cookie); fFileSystem->Root()->MakeInfoInvalid(); - if (confirm) - return _ConfirmOpen(fh, cookie); - return B_OK; } @@ -202,95 +75,18 @@ Inode::Create(const char* name, int mode, int perms, OpenFileCookie* cookie, status_t Inode::Open(int mode, OpenFileCookie* cookie) { - bool confirm; - status_t result; - cookie->fFileSystem = fFileSystem; cookie->fInfo = fInfo; cookie->fMode = mode; cookie->fSequence = 0; cookie->fLocks = NULL; - 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); - - // 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); + status_t result = OpenFile(cookie, mode); + if (result != B_OK) + return result; fFileSystem->AddOpenFile(cookie); - if (confirm) - return _ConfirmOpen(fInfo.fHandle, cookie); - return B_OK; } @@ -299,34 +95,7 @@ status_t Inode::Close(OpenFileCookie* cookie) { fFileSystem->RemoveOpenFile(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; + return CloseFile(cookie); } @@ -336,37 +105,20 @@ Inode::Read(OpenFileCookie* cookie, off_t pos, void* buffer, size_t* _length, { *eof = false; uint32 size = 0; - uint32 len = 0; + status_t result; while (size < *_length && !*eof) { - do { - RPC::Server* serv = fFileSystem->Server(); - Request request(serv); - RequestBuilder& req = request.Builder(); - - req.PutFH(fInfo.fHandle); - req.Read(cookie->fStateId, cookie->fStateSeq, pos + size, - *_length - size); - - status_t result = request.Send(cookie); - if (result != B_OK) + uint32 len = *_length - size; + result = ReadFile(cookie, pos + size, &len, + reinterpret_cast(buffer) + size, eof); + if (result != B_OK) { + if (size == 0) return result; + else + break; + } - ReplyInterpreter& reply = request.Reply(); - - if (_HandleErrors(reply.NFS4Error(), serv, cookie)) - continue; - - reply.PutFH(); - result = reply.Read(reinterpret_cast(buffer) + size, &len, - eof); - if (result != B_OK) - return result; - - size += len; - - break; - } while (true); + size += len; } *_length = size; @@ -380,74 +132,21 @@ Inode::Write(OpenFileCookie* cookie, off_t pos, const void* _buffer, size_t *_length) { uint32 size = 0; - uint32 len = 0; - uint64 fileSize; const char* buffer = reinterpret_cast(_buffer); fWriteDirty = true; while (size < *_length) { - do { - RPC::Server* serv = fFileSystem->Server(); - Request request(serv); - RequestBuilder& req = request.Builder(); - - 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) + uint32 len = *_length - size; + status_t result = WriteFile(cookie, pos + size, &len, buffer + size); + if (result != B_OK) { + if (size == 0) return result; + else + break; + } - ReplyInterpreter& reply = request.Reply(); - - // 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); + size += len; } *_length = size; @@ -464,26 +163,10 @@ Inode::Commit() { if (!fWriteDirty) return B_OK; - - do { - RPC::Server* serv = fFileSystem->Server(); - Request request(serv); - RequestBuilder& req = request.Builder(); - - 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); + status_t result = CommitWrites(); + if (result != B_OK) + return result; + fWriteDirty = false; + return B_OK; } diff --git a/src/add-ons/kernel/file_systems/nfs4/Jamfile b/src/add-ons/kernel/file_systems/nfs4/Jamfile index 0d77bb21f5..13e62e81c1 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Jamfile +++ b/src/add-ons/kernel/file_systems/nfs4/Jamfile @@ -15,6 +15,8 @@ KernelAddon nfs4 : InodeDir.cpp InodeRegular.cpp kernel_interface.cpp + NFS4Inode.cpp + NFS4Object.cpp NFS4Server.cpp ReplyInterpreter.cpp Request.cpp diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h index 8ba791de2a..e9775aaa8d 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h @@ -207,6 +207,12 @@ enum OpenFlags { OPEN4_RESULT_LOCKTYPE_POSIX = 4 }; +struct ChangeInfo { + bool fAtomic; + uint64 fBefore; + uint64 fAfter; +}; + enum WriteStable { UNSTABLE4 = 0, DATA_SYNC4 = 1, diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp new file mode 100644 index 0000000000..564690c19b --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp @@ -0,0 +1,1016 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ + + +#include "IdMap.h" +#include "Inode.h" +#include "NFS4Inode.h" +#include "Request.h" + + +status_t +NFS4Inode::GetChangeInfo(uint64* change) +{ + do { + RPC::Server* serv = fFileSystem->Server(); + Request request(serv); + RequestBuilder& req = request.Builder(); + + req.PutFH(fInfo.fHandle); + + Attribute attr[] = { FATTR4_CHANGE }; + req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); + + status_t result = request.Send(); + if (result != B_OK) + return result; + + ReplyInterpreter& reply = request.Reply(); + + if (HandleErrors(reply.NFS4Error(), serv)) + continue; + + reply.PutFH(); + + AttrValue* values; + uint32 count; + result = reply.GetAttr(&values, &count); + if (result != B_OK || count < 1) + return result; + + // FATTR4_CHANGE is mandatory + *change = values[0].fData.fValue64; + delete[] values; + + return B_OK; + } while (true); +} + + +status_t +NFS4Inode::CommitWrites() +{ + do { + RPC::Server* serv = fFileSystem->Server(); + Request request(serv); + RequestBuilder& req = request.Builder(); + + 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); +} + + +status_t +NFS4Inode::Access(uint32* allowed) +{ + do { + RPC::Server* serv = fFileSystem->Server(); + Request request(serv); + RequestBuilder& req = request.Builder(); + + req.PutFH(fInfo.fHandle); + req.Access(); + + 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.Access(NULL, allowed); + } while (true); +} + + +status_t +NFS4Inode::LookUp(const char* name, uint64* change, uint64* fileID, + FileHandle* handle) +{ + do { + RPC::Server* serv = fFileSystem->Server(); + Request request(serv); + RequestBuilder& req = request.Builder(); + + req.PutFH(fInfo.fHandle); + + Attribute dirAttr[] = { FATTR4_CHANGE }; + req.GetAttr(dirAttr, sizeof(dirAttr) / sizeof(Attribute)); + + if (!strcmp(name, "..")) + req.LookUpUp(); + else + req.LookUp(name); + + req.GetFH(); + + Attribute attr[] = { FATTR4_FSID, 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 (HandleErrors(reply.NFS4Error(), serv)) + continue; + + reply.PutFH(); + + AttrValue* values; + uint32 count; + result = reply.GetAttr(&values, &count); + if (result != B_OK) + return result; + + *change = values[0].fData.fValue64; + delete[] values; + + if (!strcmp(name, "..")) + result = reply.LookUpUp(); + else + result = reply.LookUp(); + if (result != B_OK) + return result; + + reply.GetFH(handle); + + result = reply.GetAttr(&values, &count); + if (result != B_OK) + return result; + + // FATTR4_FSID is mandatory + FileSystemId* fsid = + reinterpret_cast(values[0].fData.fPointer); + if (*fsid != fFileSystem->FsId()) { + delete[] values; + return B_ENTRY_NOT_FOUND; + } + + if (count < 2 || values[1].fAttribute != FATTR4_FILEID) + *fileID = fFileSystem->AllocFileId(); + else + *fileID = values[1].fData.fValue64; + delete[] values; + + return B_OK; + } while (true); +} + + +status_t +NFS4Inode::Link(Inode* dir, const char* name, ChangeInfo* changeInfo) +{ + do { + RPC::Server* serv = fFileSystem->Server(); + Request request(serv); + RequestBuilder& req = request.Builder(); + + req.PutFH(fInfo.fHandle); + req.SaveFH(); + req.PutFH(dir->fInfo.fHandle); + req.Link(name); + + status_t result = request.Send(); + if (result != B_OK) + return result; + + ReplyInterpreter& reply = request.Reply(); + + if (HandleErrors(reply.NFS4Error(), serv)) + continue; + + reply.PutFH(); + reply.SaveFH(); + reply.PutFH(); + + return reply.Link(&changeInfo->fBefore, &changeInfo->fAfter, + changeInfo->fAtomic); + } while (true); +} + + +status_t +NFS4Inode::ReadLink(void* buffer, size_t* length) +{ + do { + RPC::Server* serv = fFileSystem->Server(); + Request request(serv); + RequestBuilder& req = request.Builder(); + + req.PutFH(fInfo.fHandle); + req.ReadLink(); + + status_t result = request.Send(); + if (result != B_OK) + return result; + + ReplyInterpreter& reply = request.Reply(); + + if (HandleErrors(reply.NFS4Error(), serv)) + continue; + + reply.PutFH(); + + uint32 size; + result = reply.ReadLink(buffer, &size, *length); + *length = static_cast(size); + + return result; + } while (true); +} + + +status_t +NFS4Inode::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) + return result; + + ReplyInterpreter& reply = request.Reply(); + + if (HandleErrors(reply.NFS4Error(), serv)) + continue; + + reply.PutFH(); + result = reply.OpenConfirm(&cookie->fStateSeq); + if (result != B_OK) + return result; + + return B_OK; + } while (true); +} + + +status_t +NFS4Inode::GetStat(AttrValue** values, uint32* count) +{ + do { + RPC::Server* serv = fFileSystem->Server(); + Request request(serv); + RequestBuilder& req = request.Builder(); + + req.PutFH(fInfo.fHandle); + + Attribute attr[] = { FATTR4_SIZE, FATTR4_MODE, FATTR4_NUMLINKS, + FATTR4_OWNER, FATTR4_OWNER_GROUP, + FATTR4_TIME_ACCESS, FATTR4_TIME_CREATE, + FATTR4_TIME_METADATA, FATTR4_TIME_MODIFY }; + req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); + + 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.GetAttr(values, count); + } while (true); +} + + +status_t +NFS4Inode::WriteStat(OpenFileCookie* cookie, AttrValue* attrs, uint32 attrCount) +{ + do { + RPC::Server* serv = fFileSystem->Server(); + Request request(serv); + RequestBuilder& req = request.Builder(); + + req.PutFH(fInfo.fHandle); + if (cookie != NULL) + req.SetAttr(cookie->fStateId, cookie->fStateSeq, attrs, attrCount); + else + req.SetAttr(NULL, 0, attrs, attrCount); + + status_t result = request.Send(); + if (result != B_OK) + return result; + + ReplyInterpreter& reply = request.Reply(); + + if (HandleErrors(reply.NFS4Error(), serv)) + continue; + + reply.PutFH(); + result = reply.SetAttr(); + + if (result != B_OK) + return result; + + return B_OK; + } while (true); +} + + +status_t +NFS4Inode::Rename(Inode* from, Inode* to, const char* fromName, + const char* toName, ChangeInfo* fromChange, ChangeInfo* toChange, + uint64* fileID) +{ + do { + RPC::Server* serv = from->fFileSystem->Server(); + Request request(serv); + RequestBuilder& req = request.Builder(); + + req.PutFH(from->fInfo.fHandle); + req.SaveFH(); + req.PutFH(to->fInfo.fHandle); + req.Rename(fromName, toName); + + Attribute attr[] = { FATTR4_FILEID }; + req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); + req.LookUp(toName); + + status_t result = request.Send(); + if (result != B_OK) + return result; + + ReplyInterpreter& reply = request.Reply(); + + // FileHandle has expired + if (reply.NFS4Error() == NFS4ERR_FHEXPIRED) { + from->fInfo.UpdateFileHandles(from->fFileSystem); + to->fInfo.UpdateFileHandles(to->fFileSystem); + continue; + } + + // filesystem has been moved + if (reply.NFS4Error() == NFS4ERR_MOVED) { + from->fFileSystem->Migrate(serv); + continue; + } + + reply.PutFH(); + reply.SaveFH(); + reply.PutFH(); + + result = reply.Rename(&fromChange->fBefore, &fromChange->fAfter, + fromChange->fAtomic, &toChange->fBefore, &toChange->fAfter, + toChange->fAtomic); + if (result != B_OK) + return result; + + result = reply.LookUp(); + if (result != B_OK) + return result; + + AttrValue* values; + uint32 count; + result = reply.GetAttr(&values, &count); + if (result != B_OK) + return result; + + if (count == 0) + *fileID = from->fFileSystem->AllocFileId(); + else + *fileID = values[0].fData.fValue64; + + delete[] values; + + return B_OK; + } while (true); +} + + +status_t +NFS4Inode::CreateFile(const char* name, int mode, int perms, + OpenFileCookie* cookie, ChangeInfo* changeInfo, uint64* fileID, + FileHandle* handle) +{ + bool confirm; + status_t result; + + bool badOwner = false; + 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(fInfo.fHandle); + + AttrValue cattr[4]; + 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)) { + 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.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(); + + result = reply.Open(cookie->fStateId, &cookie->fStateSeq, &confirm, + &changeInfo->fBefore, &changeInfo->fAfter, &changeInfo->fAtomic); + if (result != B_OK) + return result; + + reply.GetFH(handle); + + 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(); + + break; + } while (true); + + if (confirm) + return ConfirmOpen(*handle, cookie); + + return B_OK; +} + + +status_t +NFS4Inode::OpenFile(OpenFileCookie* cookie, int mode) +{ + bool confirm; + status_t result; + 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); + + // 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); + + if (confirm) + return ConfirmOpen(fInfo.fHandle, cookie); + + return B_OK; +} + + +status_t +NFS4Inode::CloseFile(OpenFileCookie* 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(); + return reply.Close(); + } while (true); +} + + +status_t +NFS4Inode::ReadFile(OpenFileCookie* cookie, uint64 position, uint32* length, + void* buffer, bool* eof) +{ + do { + RPC::Server* serv = fFileSystem->Server(); + Request request(serv); + RequestBuilder& req = request.Builder(); + + req.PutFH(fInfo.fHandle); + req.Read(cookie->fStateId, cookie->fStateSeq, position, *length); + + status_t result = request.Send(cookie); + if (result != B_OK) + return result; + + ReplyInterpreter& reply = request.Reply(); + + if (HandleErrors(reply.NFS4Error(), serv, cookie)) + continue; + + reply.PutFH(); + result = reply.Read(buffer, length, eof); + if (result != B_OK) + return result; + + return B_OK; + } while (true); +} + + +status_t +NFS4Inode::WriteFile(OpenFileCookie* cookie, uint64 position, uint32* length, + const void* buffer) +{ + do { + RPC::Server* serv = fFileSystem->Server(); + Request request(serv); + RequestBuilder& req = request.Builder(); + + req.PutFH(fInfo.fHandle); + + req.Write(cookie->fStateId, cookie->fStateSeq, buffer, position, + *length); + + status_t result = request.Send(cookie); + if (result != B_OK) + return result; + + ReplyInterpreter& reply = request.Reply(); + + if (HandleErrors(reply.NFS4Error(), serv, cookie)) + continue; + + reply.PutFH(); + + result = reply.Write(length); + if (result != B_OK) + return result; + + return B_OK; + } while (true); +} + + +status_t +NFS4Inode::CreateObject(const char* name, const char* path, int mode, + FileType type, ChangeInfo* changeInfo, uint64* fileID, FileHandle* handle) +{ + bool badOwner = false; + + 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++; + } + + switch (type) { + case NF4DIR: + req.Create(NF4DIR, name, cattr, i); + break; + case NF4LNK: + req.Create(NF4LNK, name, cattr, i, path); + break; + default: + return B_BAD_VALUE; + } + + 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(); + result = reply.Create(&changeInfo->fBefore, &changeInfo->fAfter, + changeInfo->fAtomic); + if (result != B_OK) + return result; + + 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; + + if (count == 0) + *fileID = fFileSystem->AllocFileId(); + else + *fileID = values[0].fData.fValue64; + + delete[] values; + + return B_OK; + } while (true); +} + + +status_t +NFS4Inode::RemoveObject(const char* name, FileType type, ChangeInfo* changeInfo) +{ + do { + RPC::Server* serv = fFileSystem->Server(); + Request request(serv); + RequestBuilder& req = request.Builder(); + + req.PutFH(fInfo.fHandle); + req.LookUp(name); + AttrValue attr; + attr.fAttribute = FATTR4_TYPE; + attr.fFreePointer = false; + attr.fData.fValue32 = NF4DIR; + if (type == NF4DIR) + req.Verify(&attr, 1); + else + req.Nverify(&attr, 1); + + req.PutFH(fInfo.fHandle); + req.Remove(name); + + status_t result = request.Send(); + if (result != B_OK) + return result; + + ReplyInterpreter& reply = request.Reply(); + + if (HandleErrors(reply.NFS4Error(), serv)) + continue; + + reply.PutFH(); + result = reply.LookUp(); + if (result != B_OK) + return result; + + if (type == NF4DIR) + result = reply.Verify(); + else + result = reply.Nverify(); + + if (result == NFS4ERR_SAME && type != NF4DIR) + return B_IS_A_DIRECTORY; + if (result == NFS4ERR_NOT_SAME && type == NF4DIR) + return B_NOT_A_DIRECTORY; + if (result != B_OK) + return result; + + reply.PutFH(); + + return reply.Remove(&changeInfo->fBefore, &changeInfo->fAfter, + changeInfo->fAtomic); + } while (true); +} + + +status_t +NFS4Inode::ReadDirOnce(DirEntry** dirents, uint32* count, OpenDirCookie* cookie, + 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 +NFS4Inode::TestLock(OpenFileCookie* cookie, LockType* type, uint64* position, + uint64* length, bool& conflict) +{ + do { + RPC::Server* serv = fFileSystem->Server(); + Request request(serv); + RequestBuilder& req = request.Builder(); + + req.PutFH(fInfo.fHandle); + req.LockT(*type, *position, *length, cookie); + + 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.LockT(position, length, type); + if (reply.NFS4Error() == NFS4ERR_DENIED) { + conflict = true; + result = B_OK; + } else if (reply.NFS4Error() == NFS4_OK) + conflict = false; + + return result; + } while (true); + + return B_OK; +} + + +status_t +NFS4Inode::AcquireLock(OpenFileCookie* cookie, LockInfo* lockInfo, bool wait) +{ + do { + MutexLocker ownerLocker(lockInfo->fOwner->fLock); + + RPC::Server* serv = fFileSystem->Server(); + Request request(serv); + RequestBuilder& req = request.Builder(); + + req.PutFH(fInfo.fHandle); + req.Lock(cookie, lockInfo); + + status_t result = request.Send(); + if (result != B_OK) + return result; + + ReplyInterpreter &reply = request.Reply(); + + reply.PutFH(); + result = reply.Lock(lockInfo); + + ownerLocker.Unlock(); + if (wait && reply.NFS4Error() == NFS4ERR_DENIED) { + snooze_etc(sSecToBigTime(5), B_SYSTEM_TIMEBASE, + B_RELATIVE_TIMEOUT); + continue; + } + if (HandleErrors(reply.NFS4Error(), serv, cookie)) + continue; + + if (result != B_OK) + return result; + + return B_OK; + } while (true); +} + + +status_t +NFS4Inode::ReleaseLock(OpenFileCookie* cookie, LockInfo* lockInfo) +{ + do { + MutexLocker ownerLocker(lockInfo->fOwner->fLock); + + RPC::Server* serv = fFileSystem->Server(); + Request request(serv); + RequestBuilder& req = request.Builder(); + + req.PutFH(fInfo.fHandle); + req.LockU(lockInfo); + + status_t result = request.Send(); + if (result != B_OK) + return result; + + ReplyInterpreter &reply = request.Reply(); + + reply.PutFH(); + result = reply.LockU(lockInfo); + + ownerLocker.Unlock(); + if (HandleErrors(reply.NFS4Error(), serv, cookie)) + continue; + + if (result != B_OK) + return result; + + return B_OK; + } while (true); +} + diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h new file mode 100644 index 0000000000..4d5a6221db --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h @@ -0,0 +1,78 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ +#ifndef NFS4INODE_H +#define NFS4INODE_H + + +#include + +#include + +#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 + diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp new file mode 100644 index 0000000000..ba08e77c7c --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp @@ -0,0 +1,89 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ + + +#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; + } +} + diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Object.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Object.h new file mode 100644 index 0000000000..49b4ecf466 --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Object.h @@ -0,0 +1,29 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ +#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 + diff --git a/src/add-ons/kernel/file_systems/nfs4/RootInode.cpp b/src/add-ons/kernel/file_systems/nfs4/RootInode.cpp index 6d99f30812..efb372a6d4 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RootInode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RootInode.cpp @@ -70,7 +70,7 @@ RootInode::_UpdateInfo(bool force) ReplyInterpreter& reply = request.Reply(); - if (_HandleErrors(reply.NFS4Error(), serv)) + if (HandleErrors(reply.NFS4Error(), serv)) continue; reply.PutFH(); @@ -152,7 +152,7 @@ RootInode::ProbeMigration() if (reply.NFS4Error() == NFS4ERR_MOVED) return true; - if (_HandleErrors(reply.NFS4Error(), serv)) + if (HandleErrors(reply.NFS4Error(), serv)) continue; return false; @@ -179,7 +179,7 @@ RootInode::GetLocations(AttrValue** attrv) ReplyInterpreter& reply = request.Reply(); - if (_HandleErrors(reply.NFS4Error(), serv)) + if (HandleErrors(reply.NFS4Error(), serv)) continue; reply.PutFH(); From 7efb4c9b493ccd82c277f013238cfc78aa8ab62d Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Sat, 4 Aug 2012 00:47:13 +0200 Subject: [PATCH 153/252] nfs4: Add ACCESS cache --- .../kernel/file_systems/nfs4/DirectoryCache.h | 2 +- .../kernel/file_systems/nfs4/Inode.cpp | 102 ++++++++---------- src/add-ons/kernel/file_systems/nfs4/Inode.h | 9 +- .../kernel/file_systems/nfs4/InodeRegular.cpp | 2 +- src/add-ons/kernel/file_systems/nfs4/Jamfile | 1 + .../file_systems/nfs4/MetadataCache.cpp | 99 +++++++++++++++++ .../kernel/file_systems/nfs4/MetadataCache.h | 76 +++++++++++++ .../kernel/file_systems/nfs4/RootInode.cpp | 3 +- 8 files changed, 229 insertions(+), 65 deletions(-) create mode 100644 src/add-ons/kernel/file_systems/nfs4/MetadataCache.cpp create mode 100644 src/add-ons/kernel/file_systems/nfs4/MetadataCache.h diff --git a/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.h b/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.h index 9e880f67ff..e558b166e9 100644 --- a/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.h +++ b/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.h @@ -64,7 +64,7 @@ public: inline Inode* GetInode(); inline time_t ExpireTime(); - static const bigtime_t kExpirationTime = 5000000; + static const bigtime_t kExpirationTime = 15000000; private: SinglyLinkedList fNameCache; diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index 53394cd8f5..5c28b4bbe2 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -22,13 +22,11 @@ Inode::Inode() : - fAttrCacheExpire(0), fCache(NULL), fFileCache(NULL), fWriteCookie(NULL), fWriteDirty(false) { - mutex_init(&fAttrCacheLock, NULL); mutex_init(&fFileCacheLock, NULL); } @@ -126,7 +124,6 @@ Inode::~Inode() delete fCache; mutex_destroy(&fFileCacheLock); - mutex_destroy(&fAttrCacheLock); } @@ -142,7 +139,8 @@ Inode::RevalidateFileCache() if (change == fChange) return B_OK; - result = UpdateAttrCache(true); + struct stat st; + result = Stat(&st); if (result != B_OK) return result; @@ -150,8 +148,7 @@ Inode::RevalidateFileCache() Commit(); file_cache_delete(fFileCache); - fFileCache = file_cache_create(fFileSystem->DevId(), ID(), - fAttrCache.st_size); + fFileCache = file_cache_create(fFileSystem->DevId(), ID(), st.st_size); change = fChange; return B_OK; @@ -351,9 +348,13 @@ Inode::Access(int mode) int acc = 0; uint32 allowed; - status_t result = NFS4Inode::Access(&allowed); - if (result != B_OK) - return result; + status_t result = fMetaCache.GetAccess(geteuid(), &allowed); + if (result != B_OK) { + result = NFS4Inode::Access(&allowed); + if (result != B_OK) + return result; + fMetaCache.SetAccess(geteuid(), allowed); + } if ((allowed & ACCESS4_READ) != 0) acc |= R_OK; @@ -377,39 +378,26 @@ Inode::Access(int mode) status_t Inode::Stat(struct stat* st) { - status_t result = UpdateAttrCache(); - if (result != B_OK) - return result; - - // Do not touch other members of struct stat - st->st_size = fAttrCache.st_size; - st->st_mode = fAttrCache.st_mode; - st->st_nlink = fAttrCache.st_nlink; - st->st_uid = fAttrCache.st_uid; - st->st_gid = fAttrCache.st_gid; - st->st_atim = fAttrCache.st_atim; - st->st_ctim = fAttrCache.st_ctim; - st->st_crtim = fAttrCache.st_crtim; - st->st_mtim = fAttrCache.st_mtim; + status_t result = fMetaCache.GetStat(st); + if (result != B_OK) { + struct stat temp; + result = GetStat(&temp); + if (result != B_OK) + return result; + fMetaCache.SetStat(temp); + fMetaCache.GetStat(st); + } return B_OK; } status_t -Inode::UpdateAttrCache(bool force) +Inode::GetStat(struct stat* st) { - if (!force && fAttrCacheExpire > time(NULL)) - return B_OK; - - MutexLocker _(fAttrCacheLock); - - if (fAttrCacheExpire > time(NULL)) - return B_OK; - AttrValue* values; uint32 count; - status_t result = GetStat(&values, &count); + status_t result = NFS4Inode::GetStat(&values, &count); if (result != B_OK) return result; @@ -418,73 +406,71 @@ Inode::UpdateAttrCache(bool force) delete[] values; return B_BAD_VALUE; } - fAttrCache.st_size = values[0].fData.fValue64; + st->st_size = values[0].fData.fValue64; uint32 next = 1; - fAttrCache.st_mode = Type(); + st->st_mode = Type(); if (count >= next && values[next].fAttribute == FATTR4_MODE) { - fAttrCache.st_mode |= values[next].fData.fValue32; + st->st_mode |= values[next].fData.fValue32; next++; } else - fAttrCache.st_mode = 777; + st->st_mode = 777; if (count >= next && values[next].fAttribute == FATTR4_NUMLINKS) { - fAttrCache.st_nlink = values[next].fData.fValue32; + st->st_nlink = values[next].fData.fValue32; next++; } else - fAttrCache.st_nlink = 1; + st->st_nlink = 1; if (count >= next && values[next].fAttribute == FATTR4_OWNER) { char* owner = reinterpret_cast(values[next].fData.fPointer); if (owner != NULL && isdigit(owner[0])) - fAttrCache.st_uid = atoi(owner); + st->st_uid = atoi(owner); else - fAttrCache.st_uid = gIdMapper->GetUserId(owner); + st->st_uid = gIdMapper->GetUserId(owner); next++; } else - fAttrCache.st_uid = 0; + st->st_uid = 0; if (count >= next && values[next].fAttribute == FATTR4_OWNER_GROUP) { char* group = reinterpret_cast(values[next].fData.fPointer); if (group != NULL && isdigit(group[0])) - fAttrCache.st_gid = atoi(group); + st->st_gid = atoi(group); else - fAttrCache.st_gid = gIdMapper->GetGroupId(group); + st->st_gid = gIdMapper->GetGroupId(group); next++; } else - fAttrCache.st_gid = 0; + st->st_gid = 0; if (count >= next && values[next].fAttribute == FATTR4_TIME_ACCESS) { - memcpy(&fAttrCache.st_atim, values[next].fData.fPointer, + memcpy(&st->st_atim, values[next].fData.fPointer, sizeof(timespec)); next++; } else - memset(&fAttrCache.st_atim, 0, sizeof(timespec)); + memset(&st->st_atim, 0, sizeof(timespec)); if (count >= next && values[next].fAttribute == FATTR4_TIME_CREATE) { - memcpy(&fAttrCache.st_crtim, values[next].fData.fPointer, + memcpy(&st->st_crtim, values[next].fData.fPointer, sizeof(timespec)); next++; } else - memset(&fAttrCache.st_crtim, 0, sizeof(timespec)); + memset(&st->st_crtim, 0, sizeof(timespec)); if (count >= next && values[next].fAttribute == FATTR4_TIME_METADATA) { - memcpy(&fAttrCache.st_ctim, values[next].fData.fPointer, + memcpy(&st->st_ctim, values[next].fData.fPointer, sizeof(timespec)); next++; } else - memset(&fAttrCache.st_ctim, 0, sizeof(timespec)); + memset(&st->st_ctim, 0, sizeof(timespec)); if (count >= next && values[next].fAttribute == FATTR4_TIME_MODIFY) { - memcpy(&fAttrCache.st_mtim, values[next].fData.fPointer, + memcpy(&st->st_mtim, values[next].fData.fPointer, sizeof(timespec)); next++; } else - memset(&fAttrCache.st_mtim, 0, sizeof(timespec)); + memset(&st->st_mtim, 0, sizeof(timespec)); delete[] values; - fAttrCacheExpire = time(NULL) + kAttrCacheExpirationTime; - return B_OK; } @@ -559,7 +545,11 @@ Inode::WriteStat(const struct stat* st, uint32 mask) delete cookie; } - UpdateAttrCache(true); + fMetaCache.InvalidateStat(); + if ((mask & B_STAT_MODE) != 0 || (mask & B_STAT_UID) != 0 + || (mask & B_STAT_GID) != 0) { + fMetaCache.InvalidateAccess(); + } return result; } diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h b/src/add-ons/kernel/file_systems/nfs4/Inode.h index 0581251f8f..43892f9195 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -9,6 +9,7 @@ #define INODE_H +#include "MetadataCache.h" #include "NFS4Inode.h" @@ -85,7 +86,7 @@ protected: status_t ChildAdded(const char* name, uint64 fileID, const FileHandle& fileHandle); - status_t UpdateAttrCache(bool force = false); + status_t GetStat(struct stat* st); static inline status_t CheckLockType(short ltype, uint32 mode); @@ -93,11 +94,7 @@ protected: uint32 fType; - struct stat fAttrCache; - mutex fAttrCacheLock; - time_t fAttrCacheExpire; - static const time_t kAttrCacheExpirationTime = 60; - + MetadataCache fMetaCache; DirectoryCache* fCache; uint64 fChange; diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp index d9da7c2b9b..75b71dbef2 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp @@ -151,7 +151,7 @@ Inode::Write(OpenFileCookie* cookie, off_t pos, const void* _buffer, *_length = size; - fAttrCache.st_size = max_c(fAttrCache.st_size, *_length + pos); + fMetaCache.GrowFile(size + pos); fFileSystem->Root()->MakeInfoInvalid(); return B_OK; diff --git a/src/add-ons/kernel/file_systems/nfs4/Jamfile b/src/add-ons/kernel/file_systems/nfs4/Jamfile index 13e62e81c1..a7c16d505d 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Jamfile +++ b/src/add-ons/kernel/file_systems/nfs4/Jamfile @@ -15,6 +15,7 @@ KernelAddon nfs4 : InodeDir.cpp InodeRegular.cpp kernel_interface.cpp + MetadataCache.cpp NFS4Inode.cpp NFS4Object.cpp NFS4Server.cpp diff --git a/src/add-ons/kernel/file_systems/nfs4/MetadataCache.cpp b/src/add-ons/kernel/file_systems/nfs4/MetadataCache.cpp new file mode 100644 index 0000000000..d8ba4bec3d --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/MetadataCache.cpp @@ -0,0 +1,99 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ + + +#include "MetadataCache.h" + + +MetadataCache::MetadataCache() + : + fExpire(0) +{ + mutex_init(&fLock, NULL); +} + + +MetadataCache::~MetadataCache() +{ + mutex_destroy(&fLock); +} + + +status_t +MetadataCache::GetStat(struct stat* st) +{ + MutexLocker _(fLock); + if (fExpire > time(NULL)) { + // Do not touch other members of struct stat + st->st_size = fStatCache.st_size; + st->st_mode = fStatCache.st_mode; + st->st_nlink = fStatCache.st_nlink; + st->st_uid = fStatCache.st_uid; + st->st_gid = fStatCache.st_gid; + st->st_atim = fStatCache.st_atim; + st->st_ctim = fStatCache.st_ctim; + st->st_crtim = fStatCache.st_crtim; + st->st_mtim = fStatCache.st_mtim; + + return B_OK; + } + + return B_ERROR; +} + + +void +MetadataCache::SetStat(const struct stat& st) +{ + MutexLocker _(fLock); + fStatCache = st; + fExpire = time(NULL) + kExpirationTime; +} + + +void +MetadataCache::GrowFile(size_t newSize) +{ + MutexLocker _(fLock); + fStatCache.st_size = max_c(newSize, fStatCache.st_size); +} + + +status_t +MetadataCache::GetAccess(uid_t uid, uint32* allowed) +{ + MutexLocker _(fLock); + AVLTreeMap::Iterator it = fAccessCache.Find(uid); + if (!it.HasCurrent()) + return B_ENTRY_NOT_FOUND; + + if (it.Current().fExpire < time(NULL)) { + it.Remove(); + return B_ERROR; + } + + *allowed = it.Current().fAllowed; + + return B_OK; +} + + +void +MetadataCache::SetAccess(uid_t uid, uint32 allowed) +{ + MutexLocker _(fLock); + AVLTreeMap::Iterator it = fAccessCache.Find(uid); + if (it.HasCurrent()) + it.Remove(); + + AccessEntry entry; + entry.fAllowed = allowed; + entry.fExpire = time(NULL) + kExpirationTime; + fAccessCache.Insert(uid, entry); +} + diff --git a/src/add-ons/kernel/file_systems/nfs4/MetadataCache.h b/src/add-ons/kernel/file_systems/nfs4/MetadataCache.h new file mode 100644 index 0000000000..ecf12e70e2 --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/MetadataCache.h @@ -0,0 +1,76 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ +#ifndef METADATACACHE_H +#define METADATACACHE_H + + +#include +#include +#include +#include + + +struct AccessEntry { + time_t fExpire; + uint32 fAllowed; +}; + +class MetadataCache { +public: + MetadataCache(); + ~MetadataCache(); + + status_t GetStat(struct stat* st); + void SetStat(const struct stat& st); + void GrowFile(size_t newSize); + + status_t GetAccess(uid_t uid, uint32* allowed); + void SetAccess(uid_t uid, uint32 allowed); + + inline void InvalidateStat(); + inline void InvalidateAccess(); + + inline void Invalidate(); + + static const time_t kExpirationTime = 60; +private: + struct stat fStatCache; + time_t fExpire; + + AVLTreeMap fAccessCache; + + mutex fLock; +}; + + +inline void +MetadataCache::InvalidateStat() +{ + MutexLocker _(fLock); + fExpire = 0; +} + + +inline void +MetadataCache::InvalidateAccess() +{ + MutexLocker _(fLock); + fAccessCache.MakeEmpty(); +} + + +inline void +MetadataCache::Invalidate() +{ + InvalidateStat(); + InvalidateAccess(); +} + + +#endif // METADATACACHE_H + diff --git a/src/add-ons/kernel/file_systems/nfs4/RootInode.cpp b/src/add-ons/kernel/file_systems/nfs4/RootInode.cpp index efb372a6d4..1369d2fe2d 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RootInode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RootInode.cpp @@ -11,6 +11,7 @@ #include +#include "MetadataCache.h" #include "Request.h" @@ -126,7 +127,7 @@ RootInode::_UpdateInfo(bool force) fInfoCache.flags = 0; strncpy(fInfoCache.volume_name, fInfo.fName, B_FILE_NAME_LENGTH); - fInfoCacheExpire = time(NULL) + kAttrCacheExpirationTime; + fInfoCacheExpire = time(NULL) + MetadataCache::kExpirationTime; return B_OK; } From eeabdab19f7fe5d1a704d21cf0dbb67c0c80c8a7 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Sat, 4 Aug 2012 03:30:01 +0200 Subject: [PATCH 154/252] nfs4: Do not open too much files on server --- .../kernel/file_systems/nfs4/Cookie.cpp | 5 +- src/add-ons/kernel/file_systems/nfs4/Cookie.h | 15 +- .../kernel/file_systems/nfs4/Inode.cpp | 27 +--- src/add-ons/kernel/file_systems/nfs4/Inode.h | 26 +--- .../kernel/file_systems/nfs4/InodeRegular.cpp | 145 +++++++++++++++--- src/add-ons/kernel/file_systems/nfs4/Jamfile | 1 + .../kernel/file_systems/nfs4/NFS4Inode.cpp | 114 ++++---------- .../kernel/file_systems/nfs4/NFS4Inode.h | 24 +-- .../kernel/file_systems/nfs4/NFS4Object.cpp | 38 ++++- .../kernel/file_systems/nfs4/NFS4Object.h | 11 +- .../kernel/file_systems/nfs4/NFS4Server.cpp | 51 ++---- .../kernel/file_systems/nfs4/OpenState.cpp | 111 ++++++++++++++ .../kernel/file_systems/nfs4/OpenState.h | 46 ++++++ .../file_systems/nfs4/RequestBuilder.cpp | 25 ++- .../file_systems/nfs4/kernel_interface.cpp | 10 -- 15 files changed, 412 insertions(+), 237 deletions(-) create mode 100644 src/add-ons/kernel/file_systems/nfs4/OpenState.cpp create mode 100644 src/add-ons/kernel/file_systems/nfs4/OpenState.h diff --git a/src/add-ons/kernel/file_systems/nfs4/Cookie.cpp b/src/add-ons/kernel/file_systems/nfs4/Cookie.cpp index 016d107a20..83d0336a8b 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Cookie.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Cookie.cpp @@ -13,9 +13,6 @@ #include "Request.h" -vint64 OpenFileCookie::fLastOwnerId = 0; - - LockOwner::LockOwner(uint32 owner) : fSequence(0), @@ -164,7 +161,7 @@ OpenFileCookie::GetLockOwner(uint32 owner) if (current == NULL) return NULL; - current->fClientId = fClientId; + current->fClientId = fClientID; current->fNext = fLockOwners; if (fLockOwners != NULL) fLockOwners->fPrev = current; diff --git a/src/add-ons/kernel/file_systems/nfs4/Cookie.h b/src/add-ons/kernel/file_systems/nfs4/Cookie.h index c5b0528ce4..baeca6706d 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Cookie.h +++ b/src/add-ons/kernel/file_systems/nfs4/Cookie.h @@ -12,6 +12,7 @@ #include #include "FileSystem.h" +#include "OpenState.h" struct LockOwner { @@ -70,19 +71,13 @@ struct Cookie { }; struct OpenFileCookie : public Cookie { - uint64 fClientId; + uint64 fClientID; + + OpenState* fReadState; + OpenState* fWriteState; uint32 fMode; - FileInfo fInfo; - uint32 fStateId[3]; - uint32 fStateSeq; - - uint32 fSequence; - - uint64 fOwnerId; - static vint64 fLastOwnerId; - LockInfo* fLocks; mutex fLocksLock; diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index 5c28b4bbe2..007890e310 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -24,9 +24,11 @@ Inode::Inode() : fCache(NULL), fFileCache(NULL), - fWriteCookie(NULL), + fWriteState(NULL), + fReadState(NULL), fWriteDirty(false) { + mutex_init(&fStateLock, NULL); mutex_init(&fFileCacheLock, NULL); } @@ -123,6 +125,7 @@ Inode::~Inode() file_cache_delete(fFileCache); delete fCache; + mutex_destroy(&fStateLock); mutex_destroy(&fFileCacheLock); } @@ -479,22 +482,10 @@ status_t Inode::WriteStat(const struct stat* st, uint32 mask) { status_t result; - OpenFileCookie* cookie = NULL; AttrValue attr[6]; uint32 i = 0; if ((mask & B_STAT_SIZE) != 0) { - delete cookie; - cookie = new OpenFileCookie; - if (cookie == NULL) - return B_NO_MEMORY; - - result = Open(O_WRONLY, cookie); - if (result != B_OK) { - delete cookie; - return result; - } - attr[i].fAttribute = FATTR4_SIZE; attr[i].fFreePointer = false; attr[i].fData.fValue64 = st->st_size; @@ -538,12 +529,9 @@ Inode::WriteStat(const struct stat* st, uint32 mask) i++; } - result = NFS4Inode::WriteStat(cookie, attr, i); - - if ((mask & B_STAT_SIZE) != 0) { - Close(cookie); - delete cookie; - } + MutexLocker stateLocker(fStateLock); + result = NFS4Inode::WriteStat(fWriteState, attr, i); + stateLocker.Unlock(); fMetaCache.InvalidateStat(); if ((mask & B_STAT_MODE) != 0 || (mask & B_STAT_UID) != 0 @@ -689,7 +677,6 @@ Inode::ReleaseAllLocks(OpenFileCookie* cookie) MutexLocker _(cookie->fLocksLock); LockInfo* linfo = cookie->fLocks; while (linfo != NULL) { - MutexLocker ownerLocker(linfo->fOwner->fLock); NFS4Inode::ReleaseLock(cookie, linfo); cookie->RemoveLock(linfo, NULL); cookie->DeleteLock(linfo); diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h b/src/add-ons/kernel/file_systems/nfs4/Inode.h index 43892f9195..e4bfa9ac6b 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -11,6 +11,7 @@ #include "MetadataCache.h" #include "NFS4Inode.h" +#include "OpenState.h" class Inode : public NFS4Inode { @@ -27,9 +28,6 @@ public: inline void* FileCache(); status_t RevalidateFileCache(); - inline OpenFileCookie* WriteCookie(); - inline void SetWriteCookie(OpenFileCookie* cookie); - status_t LookUp(const char* name, ino_t* id); status_t Access(int mode); @@ -75,6 +73,9 @@ public: protected: Inode(); + status_t CreateState(const char* name, int mode, + int perms, OpenState* state); + status_t ReadDirUp(struct dirent* de, uint32 pos, uint32 size); status_t FillDirEntry(struct dirent* de, ino_t id, @@ -99,9 +100,12 @@ protected: uint64 fChange; void* fFileCache; - OpenFileCookie* fWriteCookie; mutex fFileCacheLock; + OpenState* fWriteState; + OpenState* fReadState; + mutex fStateLock; + bool fWriteDirty; }; @@ -152,19 +156,5 @@ Inode::FileCache() } -inline OpenFileCookie* -Inode::WriteCookie() -{ - return fWriteCookie; -} - - -inline void -Inode::SetWriteCookie(OpenFileCookie* cookie) -{ - fWriteCookie = cookie; -} - - #endif // INODE_H diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp index 75b71dbef2..51d41229c9 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp @@ -20,23 +20,16 @@ status_t -Inode::Create(const char* name, int mode, int perms, OpenFileCookie* cookie, - ino_t* id) -{ - cookie->fMode = mode; - cookie->fSequence = 0; - cookie->fLocks = NULL; - +Inode::CreateState(const char* name, int mode, int perms, OpenState* state) { uint64 fileID; FileHandle handle; ChangeInfo changeInfo; - status_t result = CreateFile(name, mode, perms, cookie, &changeInfo, + + status_t result = CreateFile(name, mode, perms, state, &changeInfo, &fileID, &handle); if (result != B_OK) return result; - *id = FileIdToInoT(fileID); - FileInfo fi; fi.fFileId = fileID; fi.fHandle = handle; @@ -50,7 +43,7 @@ Inode::Create(const char* name, int mode, int perms, OpenFileCookie* cookie, strcat(path, name); fi.fPath = path; - fFileSystem->InoIdMap()->AddEntry(fi, *id); + fFileSystem->InoIdMap()->AddEntry(fi, FileIdToInoT(fileID)); if (fCache->Lock() == B_OK) { if (changeInfo.fAtomic @@ -62,8 +55,59 @@ Inode::Create(const char* name, int mode, int perms, OpenFileCookie* cookie, fCache->Unlock(); } + state->fFileSystem = fFileSystem; + state->fInfo = fi; + + return B_OK; +} + + +status_t +Inode::Create(const char* name, int mode, int perms, OpenFileCookie* cookie, + ino_t* id) +{ + cookie->fMode = mode; + cookie->fLocks = NULL; + + MutexLocker _(fStateLock); + int openMode = mode & O_RWMASK; + + if (openMode == O_WRONLY || openMode == O_RDWR) { + OpenState* state = new OpenState; + status_t result = CreateState(name, O_WRONLY, perms, state); + if (result != B_OK) + return result; + + fWriteState = state; + *id = FileIdToInoT(cookie->fWriteState->fInfo.fFileId); + cookie->fWriteState = fWriteState; + } + + if (openMode == O_RDONLY || openMode == O_RDWR) { + OpenState* state = new OpenState; + state->fInfo = fInfo; + state->fFileSystem = fFileSystem; + + status_t result; + if (openMode == O_RDWR) + result = OpenFile(state, O_RDONLY); + else + result = CreateState(name, O_RDONLY, perms, state); + + if (result != B_OK) { + if (fWriteState != NULL) + if (fWriteState->ReleaseReference() == 1) + fWriteState = NULL; + return result; + } + + fReadState = state; + *id = FileIdToInoT(cookie->fReadState->fInfo.fFileId); + cookie->fReadState = fReadState; + } + cookie->fFileSystem = fFileSystem; - cookie->fInfo = fi; + cookie->fClientID = fFileSystem->NFSServer()->ClientId(); fFileSystem->AddOpenFile(cookie); fFileSystem->Root()->MakeInfoInvalid(); @@ -75,15 +119,59 @@ Inode::Create(const char* name, int mode, int perms, OpenFileCookie* cookie, status_t Inode::Open(int mode, OpenFileCookie* cookie) { - cookie->fFileSystem = fFileSystem; - cookie->fInfo = fInfo; - cookie->fMode = mode; - cookie->fSequence = 0; - cookie->fLocks = NULL; + MutexLocker _(fStateLock); + int openMode = mode & O_RWMASK; - status_t result = OpenFile(cookie, mode); - if (result != B_OK) - return result; + if (openMode == O_WRONLY || openMode == O_RDWR) { + if (fWriteState == NULL) { + OpenState* state = new OpenState; + if (state == NULL) + return B_NO_MEMORY; + + state->fInfo = fInfo; + state->fFileSystem = fFileSystem; + status_t result = OpenFile(state, O_WRONLY); + if (result != B_OK) + return result; + + fWriteState = state; + } else + fWriteState->AcquireReference(); + + cookie->fWriteState = fWriteState; + } + + if (openMode == O_RDONLY || openMode == O_RDWR) { + if (fReadState == NULL) { + OpenState* state = new OpenState; + if (state == NULL) { + if (fWriteState != NULL) + if (fWriteState->ReleaseReference() == 1) + fWriteState = NULL; + return B_NO_MEMORY; + } + + state->fInfo = fInfo; + state->fFileSystem = fFileSystem; + status_t result = OpenFile(state, O_RDONLY); + if (result != B_OK) { + if (fWriteState != NULL) + if (fWriteState->ReleaseReference() == 1) + fWriteState = NULL; + return result; + } + + fReadState = state; + } else + fReadState->AcquireReference(); + + cookie->fReadState = fReadState; + } + + cookie->fClientID = fFileSystem->NFSServer()->ClientId(); + cookie->fFileSystem = fFileSystem; + cookie->fMode = mode; + cookie->fLocks = NULL; fFileSystem->AddOpenFile(cookie); @@ -95,7 +183,17 @@ status_t Inode::Close(OpenFileCookie* cookie) { fFileSystem->RemoveOpenFile(cookie); - return CloseFile(cookie); + + MutexLocker _(fStateLock); + if (cookie->fWriteState != NULL) + if (cookie->fWriteState->ReleaseReference() == 1) + fWriteState = NULL; + + if (cookie->fReadState != NULL) + if (cookie->fReadState->ReleaseReference() == 1) + fReadState = NULL; + + return B_OK; } @@ -109,7 +207,7 @@ Inode::Read(OpenFileCookie* cookie, off_t pos, void* buffer, size_t* _length, status_t result; while (size < *_length && !*eof) { uint32 len = *_length - size; - result = ReadFile(cookie, pos + size, &len, + result = ReadFile(cookie, fReadState, pos + size, &len, reinterpret_cast(buffer) + size, eof); if (result != B_OK) { if (size == 0) @@ -138,7 +236,8 @@ Inode::Write(OpenFileCookie* cookie, off_t pos, const void* _buffer, while (size < *_length) { uint32 len = *_length - size; - status_t result = WriteFile(cookie, pos + size, &len, buffer + size); + status_t result = WriteFile(cookie, fWriteState, pos + size, &len, + buffer + size); if (result != B_OK) { if (size == 0) return result; diff --git a/src/add-ons/kernel/file_systems/nfs4/Jamfile b/src/add-ons/kernel/file_systems/nfs4/Jamfile index a7c16d505d..16a0306a88 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Jamfile +++ b/src/add-ons/kernel/file_systems/nfs4/Jamfile @@ -19,6 +19,7 @@ KernelAddon nfs4 : NFS4Inode.cpp NFS4Object.cpp NFS4Server.cpp + OpenState.cpp ReplyInterpreter.cpp Request.cpp RequestBuilder.cpp diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp index 564690c19b..a95c3b9700 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp @@ -244,38 +244,6 @@ NFS4Inode::ReadLink(void* buffer, size_t* length) } -status_t -NFS4Inode::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) - return result; - - ReplyInterpreter& reply = request.Reply(); - - if (HandleErrors(reply.NFS4Error(), serv)) - continue; - - reply.PutFH(); - result = reply.OpenConfirm(&cookie->fStateSeq); - if (result != B_OK) - return result; - - return B_OK; - } while (true); -} - - status_t NFS4Inode::GetStat(AttrValue** values, uint32* count) { @@ -309,7 +277,7 @@ NFS4Inode::GetStat(AttrValue** values, uint32* count) status_t -NFS4Inode::WriteStat(OpenFileCookie* cookie, AttrValue* attrs, uint32 attrCount) +NFS4Inode::WriteStat(OpenState* state, AttrValue* attrs, uint32 attrCount) { do { RPC::Server* serv = fFileSystem->Server(); @@ -317,8 +285,8 @@ NFS4Inode::WriteStat(OpenFileCookie* cookie, AttrValue* attrs, uint32 attrCount) RequestBuilder& req = request.Builder(); req.PutFH(fInfo.fHandle); - if (cookie != NULL) - req.SetAttr(cookie->fStateId, cookie->fStateSeq, attrs, attrCount); + if (state != NULL) + req.SetAttr(state->fStateID, state->fStateSeq, attrs, attrCount); else req.SetAttr(NULL, 0, attrs, attrCount); @@ -414,7 +382,7 @@ NFS4Inode::Rename(Inode* from, Inode* to, const char* fromName, status_t NFS4Inode::CreateFile(const char* name, int mode, int perms, - OpenFileCookie* cookie, ChangeInfo* changeInfo, uint64* fileID, + OpenState* state, ChangeInfo* changeInfo, uint64* fileID, FileHandle* handle) { bool confirm; @@ -422,13 +390,13 @@ NFS4Inode::CreateFile(const char* name, int mode, int perms, bool badOwner = false; do { - cookie->fClientId = fFileSystem->NFSServer()->ClientId(); + state->fClientID = fFileSystem->NFSServer()->ClientId(); RPC::Server* serv = fFileSystem->Server(); Request request(serv); RequestBuilder& req = request.Builder(); - cookie->fOwnerId = atomic_add64(&cookie->fLastOwnerId, 1); + state->fOwnerID = atomic_add64(&state->fLastOwnerID, 1); req.PutFH(fInfo.fHandle); @@ -459,8 +427,8 @@ NFS4Inode::CreateFile(const char* name, int mode, int perms, i++; } - req.Open(CLAIM_NULL, cookie->fSequence++, sModeToAccess(mode), - cookie->fClientId, OPEN4_CREATE, cookie->fOwnerId, name, cattr, + req.Open(CLAIM_NULL, state->fSequence++, sModeToAccess(mode), + state->fClientID, OPEN4_CREATE, state->fOwnerID, name, cattr, i, (mode & O_EXCL) == O_EXCL); req.GetFH(); @@ -485,7 +453,7 @@ NFS4Inode::CreateFile(const char* name, int mode, int perms, reply.PutFH(); - result = reply.Open(cookie->fStateId, &cookie->fStateSeq, &confirm, + result = reply.Open(state->fStateID, &state->fStateSeq, &confirm, &changeInfo->fBefore, &changeInfo->fAfter, &changeInfo->fAtomic); if (result != B_OK) return result; @@ -508,26 +476,28 @@ NFS4Inode::CreateFile(const char* name, int mode, int perms, break; } while (true); + state->fOpened = true; + if (confirm) - return ConfirmOpen(*handle, cookie); + return ConfirmOpen(*handle, state); return B_OK; } status_t -NFS4Inode::OpenFile(OpenFileCookie* cookie, int mode) +NFS4Inode::OpenFile(OpenState* state, int mode) { bool confirm; status_t result; do { - cookie->fClientId = fFileSystem->NFSServer()->ClientId(); + state->fClientID = fFileSystem->NFSServer()->ClientId(); RPC::Server* serv = fFileSystem->Server(); Request request(serv); RequestBuilder& req = request.Builder(); - cookie->fOwnerId = atomic_add64(&cookie->fLastOwnerId, 1); + state->fOwnerID = atomic_add64(&state->fLastOwnerID, 1); // Since we are opening the file using a pair (parentFH, name) we // need to check for race conditions. @@ -556,12 +526,12 @@ NFS4Inode::OpenFile(OpenFileCookie* cookie, int mode) 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, + req.Open(CLAIM_NULL, state->fSequence++, sModeToAccess(mode), + state->fClientID, OPEN4_CREATE, state->fOwnerID, fInfo.fName, &attr, 1, false); } else - req.Open(CLAIM_NULL, cookie->fSequence++, sModeToAccess(mode), - cookie->fClientId, OPEN4_NOCREATE, cookie->fOwnerId, fInfo.fName); + req.Open(CLAIM_NULL, state->fSequence++, sModeToAccess(mode), + state->fClientID, OPEN4_NOCREATE, state->fOwnerID, fInfo.fName); result = request.Send(); if (result != B_OK) @@ -588,22 +558,25 @@ NFS4Inode::OpenFile(OpenFileCookie* cookie, int mode) } reply.PutFH(); - result = reply.Open(cookie->fStateId, &cookie->fStateSeq, &confirm); + result = reply.Open(state->fStateID, &state->fStateSeq, &confirm); if (result != B_OK) return result; break; } while (true); + state->fOpened = true; + if (confirm) - return ConfirmOpen(fInfo.fHandle, cookie); + return ConfirmOpen(fInfo.fHandle, state); return B_OK; } status_t -NFS4Inode::CloseFile(OpenFileCookie* cookie) +NFS4Inode::ReadFile(OpenFileCookie* cookie, OpenState* state, uint64 position, + uint32* length, void* buffer, bool* eof) { do { RPC::Server* serv = fFileSystem->Server(); @@ -611,34 +584,7 @@ NFS4Inode::CloseFile(OpenFileCookie* cookie) 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(); - return reply.Close(); - } while (true); -} - - -status_t -NFS4Inode::ReadFile(OpenFileCookie* cookie, uint64 position, uint32* length, - void* buffer, bool* eof) -{ - do { - RPC::Server* serv = fFileSystem->Server(); - Request request(serv); - RequestBuilder& req = request.Builder(); - - req.PutFH(fInfo.fHandle); - req.Read(cookie->fStateId, cookie->fStateSeq, position, *length); + req.Read(state->fStateID, state->fStateSeq, position, *length); status_t result = request.Send(cookie); if (result != B_OK) @@ -660,9 +606,10 @@ NFS4Inode::ReadFile(OpenFileCookie* cookie, uint64 position, uint32* length, status_t -NFS4Inode::WriteFile(OpenFileCookie* cookie, uint64 position, uint32* length, - const void* buffer) +NFS4Inode::WriteFile(OpenFileCookie* cookie, OpenState* state, uint64 position, + uint32* length, const void* buffer) { + do { RPC::Server* serv = fFileSystem->Server(); Request request(serv); @@ -670,8 +617,7 @@ NFS4Inode::WriteFile(OpenFileCookie* cookie, uint64 position, uint32* length, req.PutFH(fInfo.fHandle); - req.Write(cookie->fStateId, cookie->fStateSeq, buffer, position, - *length); + req.Write(state->fStateID, state->fStateSeq, buffer, position, *length); status_t result = request.Send(cookie); if (result != B_OK) diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h index 4d5a6221db..027f6a4917 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h @@ -13,6 +13,9 @@ #include +#include "Cookie.h" +#include "FileInfo.h" +#include "FileSystem.h" #include "NFS4Object.h" #include "ReplyInterpreter.h" @@ -38,19 +41,20 @@ protected: ChangeInfo* toChange, uint64* fileID); status_t GetStat(AttrValue** values, uint32* count); - status_t WriteStat(OpenFileCookie* cookie, AttrValue* attrs, + status_t WriteStat(OpenState* state, AttrValue* attrs, uint32 attrCount); status_t CreateFile(const char* name, int mode, int perms, - OpenFileCookie* cookie, ChangeInfo* changeInfo, + OpenState* state, ChangeInfo* changeInfo, uint64* fileID, FileHandle* handle); - status_t OpenFile(OpenFileCookie* cookie, int mode); - status_t CloseFile(OpenFileCookie* cookie); + status_t OpenFile(OpenState* state, int mode); - 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 ReadFile(OpenFileCookie* cookie, OpenState* state, + uint64 position, uint32* length, void* buffer, + bool* eof); + status_t WriteFile(OpenFileCookie* cookie, OpenState* state, + uint64 position, uint32* length, + const void* buffer); status_t CreateObject(const char* name, const char* path, int mode, FileType type, ChangeInfo* changeInfo, @@ -67,10 +71,6 @@ protected: status_t AcquireLock(OpenFileCookie* cookie, LockInfo* lockInfo, bool wait); status_t ReleaseLock(OpenFileCookie* cookie, LockInfo* lockInfo); - - status_t ConfirmOpen(const FileHandle& fileHandle, - OpenFileCookie* cookie); - }; diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp index ba08e77c7c..e5db3e618c 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp @@ -7,7 +7,10 @@ */ +#include "Cookie.h" +#include "FileSystem.h" #include "NFS4Object.h" +#include "Request.h" bool @@ -59,7 +62,7 @@ NFS4Object::HandleErrors(uint32 nfs4Error, RPC::Server* serv, // server has rebooted, reclaim share and try again case NFS4ERR_STALE_CLIENTID: case NFS4ERR_STALE_STATEID: - fFileSystem->NFSServer()->ServerRebooted(cookie->fClientId); + fFileSystem->NFSServer()->ServerRebooted(cookie->fClientID); return true; // FileHandle has expired @@ -77,7 +80,7 @@ NFS4Object::HandleErrors(uint32 nfs4Error, RPC::Server* serv, // lease has expired case NFS4ERR_EXPIRED: if (cookie != NULL) { - fFileSystem->NFSServer()->ClientId(cookie->fClientId, true); + fFileSystem->NFSServer()->ClientId(cookie->fClientID, true); return true; } return false; @@ -87,3 +90,34 @@ NFS4Object::HandleErrors(uint32 nfs4Error, RPC::Server* serv, } } + +status_t +NFS4Object::ConfirmOpen(const FileHandle& fh, OpenState* state) +{ + do { + RPC::Server* serv = fFileSystem->Server(); + Request request(serv); + + RequestBuilder& req = request.Builder(); + + req.PutFH(fh); + req.OpenConfirm(state->fSequence++, state->fStateID, state->fStateSeq); + + status_t result = request.Send(); + if (result != B_OK) + return result; + + ReplyInterpreter& reply = request.Reply(); + + if (HandleErrors(reply.NFS4Error(), serv)) + continue; + + reply.PutFH(); + result = reply.OpenConfirm(&state->fStateSeq); + if (result != B_OK) + return result; + + return B_OK; + } while (true); +} + diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Object.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Object.h index 49b4ecf466..7ffcf4b9a1 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Object.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Object.h @@ -8,18 +8,21 @@ #ifndef NFS4OBJECT_H #define NFS4OBJECT_H - -#include "Cookie.h" -#include "FileSystem.h" +#include "FileInfo.h" #include "NFS4Defs.h" +#include "RPCServer.h" +class OpenFileCookie; +class OpenState; + class NFS4Object { public: bool HandleErrors(uint32 nfs4Error, RPC::Server* serv, OpenFileCookie* cookie = NULL); -protected: + status_t ConfirmOpen(const FileHandle& fileHandle, OpenState* state); + FileInfo fInfo; FileSystem* fFileSystem; }; diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp index f3ea764525..412a653866 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp @@ -59,6 +59,7 @@ NFS4Server::ServerRebooted(uint64 clientId) while (fs != NULL) { OpenFileCookie* current = fs->OpenFilesLock(); while (current != NULL) { + current->fClientID = fClientId; _ReclaimOpen(current); _ReclaimLocks(current); current = current->fNext; @@ -74,47 +75,10 @@ NFS4Server::ServerRebooted(uint64 clientId) status_t NFS4Server::_ReclaimOpen(OpenFileCookie* cookie) { - if (cookie->fClientId == fClientId) - return B_OK; - - cookie->fClientId = fClientId; - - Request request(fServer); - RequestBuilder& req = request.Builder(); - - req.PutFH(cookie->fInfo.fHandle); - req.Open(CLAIM_PREVIOUS, cookie->fSequence++, sModeToAccess(cookie->fMode), - cookie->fClientId, OPEN4_NOCREATE, cookie->fOwnerId, NULL); - - status_t result = request.Send(); - if (result != B_OK) - return result; - - ReplyInterpreter& reply = request.Reply(); - - reply.PutFH(); - - bool confirm; - result = reply.Open(cookie->fStateId, &cookie->fStateSeq, &confirm); - if (result != B_OK) - return result; - - if (confirm) { - request.Reset(); - - req.PutFH(cookie->fInfo.fHandle); - req.OpenConfirm(cookie->fSequence++, cookie->fStateId, - cookie->fStateSeq); - - result = request.Send(); - if (result != B_OK) - return result; - - reply.PutFH(); - result = reply.OpenConfirm(&cookie->fStateSeq); - if (result != B_OK) - return result; - } + if (cookie->fWriteState != NULL) + cookie->fWriteState->Reclaim(fClientId); + if (cookie->fReadState != NULL) + cookie->fReadState->Reclaim(fClientId); return B_OK; } @@ -136,7 +100,10 @@ NFS4Server::_ReclaimLocks(OpenFileCookie* cookie) Request request(fServer); RequestBuilder& req = request.Builder(); - req.PutFH(cookie->fInfo.fHandle); + if (cookie->fWriteState != NULL) + req.PutFH(cookie->fWriteState->fInfo.fHandle); + else + req.PutFH(cookie->fReadState->fInfo.fHandle); req.Lock(cookie, linfo, true); status_t result = request.Send(); diff --git a/src/add-ons/kernel/file_systems/nfs4/OpenState.cpp b/src/add-ons/kernel/file_systems/nfs4/OpenState.cpp new file mode 100644 index 0000000000..26a4df52e5 --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/OpenState.cpp @@ -0,0 +1,111 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ + + +#include "OpenState.h" + +#include + +#include "FileSystem.h" +#include "Request.h" + + +vint64 OpenState::fLastOwnerID = 0; + +OpenState::OpenState() + : + fSequence(0), + fOpened(false) +{ + mutex_init(&fLock, NULL); +} + + +OpenState::~OpenState() +{ + Close(); + mutex_destroy(&fLock); +} + + +status_t +OpenState::Reclaim(uint64 newClientID) +{ + if (!fOpened) + return B_OK; + + MutexLocker _(fLock); + + if (fClientID == newClientID) + return B_OK; + fClientID = newClientID; + + bool confirm; + do { + RPC::Server* server = fFileSystem->Server(); + Request request(server); + RequestBuilder& req = request.Builder(); + + req.PutFH(fInfo.fHandle); + req.Open(CLAIM_PREVIOUS, fSequence++, sModeToAccess(fMode), newClientID, + OPEN4_NOCREATE, fOwnerID, NULL); + + status_t result = request.Send(); + if (result != B_OK) + return result; + + ReplyInterpreter& reply = request.Reply(); + + if (HandleErrors(reply.NFS4Error(), server)) + continue; + + reply.PutFH(); + + result = reply.Open(fStateID, &fStateSeq, &confirm); + if (result != B_OK) + return result; + } while (true); + + if (confirm) + return ConfirmOpen(fInfo.fHandle, this); + + return B_OK; +} + + +status_t +OpenState::Close() +{ + if (!fOpened) + return B_OK; + + MutexLocker _(fLock); + fOpened = false; + + do { + RPC::Server* serv = fFileSystem->Server(); + Request request(serv); + RequestBuilder& req = request.Builder(); + + req.PutFH(fInfo.fHandle); + req.Close(fSequence++, fStateID, fStateSeq); + + 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.Close(); + } while (true); +} + diff --git a/src/add-ons/kernel/file_systems/nfs4/OpenState.h b/src/add-ons/kernel/file_systems/nfs4/OpenState.h new file mode 100644 index 0000000000..00da687bd2 --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/OpenState.h @@ -0,0 +1,46 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ +#ifndef OPENSTATE_H +#define OPENSTATE_H + + +#include +#include +#include + +#include "NFS4Object.h" + + +struct OpenState : public NFS4Object, public KernelReferenceable { + OpenState(); + ~OpenState(); + + uint64 fClientID; + + int fMode; + mutex fLock; + + uint32 fStateID[3]; + uint32 fStateSeq; + + uint32 fSequence; + + uint64 fOwnerID; + static vint64 fLastOwnerID; + + bool fOpened; + + + status_t Reclaim(uint64 newClientID); + + status_t Close(); +}; + + +#endif // OPENSTATE_H + diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp index d4b676cf00..3833faf66a 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp @@ -171,11 +171,14 @@ void RequestBuilder::_GenerateLockOwner(XDR::WriteStream& stream, OpenFileCookie* cookie, LockOwner* owner) { - stream.AddUHyper(cookie->fClientId); + stream.AddUHyper(cookie->fClientID); uint64 lockOwner[2]; lockOwner[0] = owner->fOwner; - lockOwner[1] = cookie->fInfo.fFileId; + if (cookie->fWriteState != NULL) + lockOwner[1] = cookie->fWriteState->fInfo.fFileId; + else + lockOwner[1] = cookie->fReadState->fInfo.fFileId; stream.AddOpaque(lockOwner, sizeof(lockOwner)); } @@ -202,11 +205,17 @@ RequestBuilder::Lock(OpenFileCookie* cookie, LockInfo* lock, bool reclaim) fRequest->Stream().AddBoolean(true); // new lock owner // open seq stateid - fRequest->Stream().AddUInt(cookie->fSequence++); - fRequest->Stream().AddUInt(cookie->fStateSeq); - fRequest->Stream().AddUInt(cookie->fStateId[0]); - fRequest->Stream().AddUInt(cookie->fStateId[1]); - fRequest->Stream().AddUInt(cookie->fStateId[2]); + OpenState* state; + if (lock->fType == READ_LT || lock->fType == READW_LT) + state = cookie->fReadState; + else + state = cookie->fWriteState; + + fRequest->Stream().AddUInt(state->fSequence++); + fRequest->Stream().AddUInt(state->fStateSeq); + fRequest->Stream().AddUInt(state->fStateID[0]); + fRequest->Stream().AddUInt(state->fStateID[1]); + fRequest->Stream().AddUInt(state->fStateID[2]); // lock seq owner fRequest->Stream().AddUInt(lock->fOwner->fSequence++); @@ -246,7 +255,7 @@ RequestBuilder::LockT(LockType type, uint64 pos, uint64 len, fRequest->Stream().AddUHyper(pos); fRequest->Stream().AddUHyper(len); - fRequest->Stream().AddUHyper(cookie->fClientId); + fRequest->Stream().AddUHyper(cookie->fClientID); uint32 owner = find_thread(NULL); fRequest->Stream().AddOpaque(&owner, sizeof(owner)); 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 560a7a9355..cc58c5593b 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -253,12 +253,6 @@ nfs4_write_pages(fs_volume* _volume, fs_vnode* vnode, void* _cookie, off_t pos, Inode* inode = reinterpret_cast(vnode->private_node); OpenFileCookie* cookie = reinterpret_cast(_cookie); - if (cookie == NULL) { - cookie = inode->WriteCookie(); - if (cookie == NULL) - return B_BAD_VALUE; - } - status_t result; uint32 ioSize = inode->GetFileSystem()->Root()->IOSize(); for (size_t i = 0; i < count; i++) { @@ -462,9 +456,6 @@ nfs4_free_cookie(fs_volume* volume, fs_vnode* vnode, void* _cookie) file_cache_sync(inode->FileCache()); inode->Commit(); - if (inode->WriteCookie() == cookie) - inode->SetWriteCookie(NULL); - inode->Close(cookie); delete cookie; @@ -512,7 +503,6 @@ nfs4_write(fs_volume* volume, fs_vnode* vnode, void* _cookie, off_t pos, if (result != B_OK) return result; - inode->SetWriteCookie(cookie); return file_cache_write(inode->FileCache(), cookie, pos, _buffer, length); } From 24128e493f63be1b913bf8a5006f94addf22043f Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Sat, 4 Aug 2012 04:40:22 +0200 Subject: [PATCH 155/252] nfs4: Send the server client's network address --- .../kernel/file_systems/nfs4/Connection.cpp | 100 +++++++-- .../kernel/file_systems/nfs4/Connection.h | 8 + .../file_systems/nfs4/RequestBuilder.cpp | 14 +- src/system/kernel/util/Jamfile | 1 + src/system/kernel/util/inet_ntop.c | 202 ++++++++++++++++++ 5 files changed, 309 insertions(+), 16 deletions(-) create mode 100644 src/system/kernel/util/inet_ntop.c diff --git a/src/add-ons/kernel/file_systems/nfs4/Connection.cpp b/src/add-ons/kernel/file_systems/nfs4/Connection.cpp index af01bae305..6f14ed8e58 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Connection.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Connection.cpp @@ -57,6 +57,93 @@ ServerAddress::ServerAddress() } +const char* +ServerAddress::ProtocolString() const +{ + static const char* tcpName = "tcp"; + static const char* udpName = "udp"; + static const char* unknown = ""; + + switch (fProtocol) { + case IPPROTO_TCP: + return tcpName; + case IPPROTO_UDP: + return udpName; + default: + return unknown; + } +} + + +char* +ServerAddress::UniversalAddress() const +{ + const sockaddr* address = reinterpret_cast(&fAddress); + + char* uAddr = reinterpret_cast(malloc(INET6_ADDRSTRLEN + 16)); + if (uAddr == NULL) + return NULL; + + if (inet_ntop(address->sa_family, InAddr(), uAddr, AddressSize()) == NULL) + return NULL; + + char port[16]; + sprintf(port, ".%d.%d", Port() >> 8, Port() & 0xff); + strcat(uAddr, port); + + return uAddr; +} + + +socklen_t +ServerAddress::AddressSize() const +{ + switch (reinterpret_cast(&fAddress)->sa_family) { + case AF_INET: + return sizeof(sockaddr_in); + case AF_INET6: + return sizeof(sockaddr_in6); + default: + return 0; + } +} + + +uint16 +ServerAddress::Port() const +{ + uint16 port; + + switch (reinterpret_cast(&fAddress)->sa_family) { + case AF_INET: + port = reinterpret_cast(&fAddress)->sin_port; + break; + case AF_INET6: + port = reinterpret_cast(&fAddress)->sin6_port; + break; + default: + port = 0; + } + + return ntohs(port); +} + + +const void* +ServerAddress::InAddr() const +{ + switch (reinterpret_cast(&fAddress)->sa_family) { + case AF_INET: + return &reinterpret_cast(&fAddress)->sin_addr; + case AF_INET6: + return &reinterpret_cast(&fAddress)->sin6_addr; + default: + return NULL; + } +} + + + status_t ServerAddress::ResolveName(const char* name, ServerAddress* address) { @@ -143,18 +230,7 @@ Connection::GetLocalAddress(ServerAddress* address) { address->fProtocol = fServerAddress.fProtocol; - socklen_t addressSize; - switch (reinterpret_cast(&fServerAddress)->sa_family) { - case AF_INET: - addressSize = sizeof(sockaddr_in); - break; - case AF_INET6: - addressSize = sizeof(sockaddr_in6); - break; - default: - return B_BAD_VALUE; - } - + socklen_t addressSize = fServerAddress.AddressSize(); return getsockname(fSocket, (struct sockaddr*)&address->fAddress, &addressSize); } diff --git a/src/add-ons/kernel/file_systems/nfs4/Connection.h b/src/add-ons/kernel/file_systems/nfs4/Connection.h index 2da2f6e5b2..e16e2cdd8d 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Connection.h +++ b/src/add-ons/kernel/file_systems/nfs4/Connection.h @@ -26,6 +26,14 @@ struct ServerAddress { ServerAddress(); + const char* ProtocolString() const; + char* UniversalAddress() const; + + socklen_t AddressSize() const; + + uint16 Port() const; + const void* InAddr() const; + static status_t ResolveName(const char* name, ServerAddress* address); }; diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp index 3833faf66a..9c44aa2815 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp @@ -636,10 +636,16 @@ RequestBuilder::SetClientID(const RPC::Server* server) if (result != B_OK) return result; - // Callbacks are currently not supported - fRequest->Stream().AddUInt(0); - fRequest->Stream().AddOpaque(NULL, 0); - fRequest->Stream().AddOpaque(NULL, 0); + fRequest->Stream().AddUInt(0x40000000); + + ServerAddress local = server->LocalID(); + fRequest->Stream().AddString(local.ProtocolString()); + char* uAddr = local.UniversalAddress(); + if (uAddr == NULL) + return B_NO_MEMORY; + fRequest->Stream().AddString(uAddr); + free(uAddr); + fRequest->Stream().AddUInt(0); fOpCount++; diff --git a/src/system/kernel/util/Jamfile b/src/system/kernel/util/Jamfile index 831b0af209..02ce7ce690 100644 --- a/src/system/kernel/util/Jamfile +++ b/src/system/kernel/util/Jamfile @@ -6,6 +6,7 @@ KernelMergeObject kernel_util.o : AVLTreeBase.cpp hostname.cpp inet_addr.c + inet_ntop.c kernel_cpp.cpp KernelReferenceable.cpp khash.cpp diff --git a/src/system/kernel/util/inet_ntop.c b/src/system/kernel/util/inet_ntop.c new file mode 100644 index 0000000000..ba3605e760 --- /dev/null +++ b/src/system/kernel/util/inet_ntop.c @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996-1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static const char rcsid[] = "$Id: inet_ntop.c,v 1.5 2005/11/03 22:59:52 marka Exp $"; +#endif /* LIBC_SCCS and not lint */ + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#ifdef SPRINTF_CHAR +# define SPRINTF(x) strlen(sprintf/**/x) +#else +# define SPRINTF(x) ((size_t)sprintf x) +#endif + +/*% + * WARNING: Don't even consider trying to compile this on a system where + * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX. + */ + +static const char *inet_ntop4 __P((const u_char *src, char *dst, size_t size)); +static const char *inet_ntop6 __P((const u_char *src, char *dst, size_t size)); + +/* char * + * inet_ntop(af, src, dst, size) + * convert a network format address to presentation format. + * return: + * pointer to presentation format address (`dst'), or NULL (see errno). + * author: + * Paul Vixie, 1996. + */ +const char * +inet_ntop(af, src, dst, size) + int af; + const void *src; + char *dst; + socklen_t size; +{ + switch (af) { + case AF_INET: + return (inet_ntop4(src, dst, size)); + case AF_INET6: + return (inet_ntop6(src, dst, size)); + default: + errno = EAFNOSUPPORT; + return (NULL); + } + /* NOTREACHED */ +} + +/* const char * + * inet_ntop4(src, dst, size) + * format an IPv4 address + * return: + * `dst' (as a const) + * notes: + * (1) uses no statics + * (2) takes a u_char* not an in_addr as input + * author: + * Paul Vixie, 1996. + */ +static const char * +inet_ntop4(src, dst, size) + const u_char *src; + char *dst; + size_t size; +{ + static const char fmt[] = "%u.%u.%u.%u"; + char tmp[sizeof "255.255.255.255"]; + + if (SPRINTF((tmp, fmt, src[0], src[1], src[2], src[3])) >= size) { + errno = ENOSPC; + return (NULL); + } + strcpy(dst, tmp); + return (dst); +} + +/* const char * + * inet_ntop6(src, dst, size) + * convert IPv6 binary address into presentation (printable) format + * author: + * Paul Vixie, 1996. + */ +static const char * +inet_ntop6(src, dst, size) + const u_char *src; + char *dst; + size_t size; +{ + /* + * Note that int32_t and int16_t need only be "at least" large enough + * to contain a value of the specified size. On some systems, like + * Crays, there is no such thing as an integer variable with 16 bits. + * Keep this in mind if you think this function should have been coded + * to use pointer overlays. All the world's not a VAX. + */ + char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp; + struct { int base, len; } best, cur; + u_int words[NS_IN6ADDRSZ / NS_INT16SZ]; + int i; + + /* + * Preprocess: + * Copy the input (bytewise) array into a wordwise array. + * Find the longest run of 0x00's in src[] for :: shorthanding. + */ + memset(words, '\0', sizeof words); + for (i = 0; i < NS_IN6ADDRSZ; i++) + words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3)); + best.base = -1; + best.len = 0; + cur.base = -1; + cur.len = 0; + for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) { + if (words[i] == 0) { + if (cur.base == -1) + cur.base = i, cur.len = 1; + else + cur.len++; + } else { + if (cur.base != -1) { + if (best.base == -1 || cur.len > best.len) + best = cur; + cur.base = -1; + } + } + } + if (cur.base != -1) { + if (best.base == -1 || cur.len > best.len) + best = cur; + } + if (best.base != -1 && best.len < 2) + best.base = -1; + + /* + * Format the result. + */ + tp = tmp; + for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) { + /* Are we inside the best run of 0x00's? */ + if (best.base != -1 && i >= best.base && + i < (best.base + best.len)) { + if (i == best.base) + *tp++ = ':'; + continue; + } + /* Are we following an initial run of 0x00s or any real hex? */ + if (i != 0) + *tp++ = ':'; + /* Is this address an encapsulated IPv4? */ + if (i == 6 && best.base == 0 && (best.len == 6 || + (best.len == 7 && words[7] != 0x0001) || + (best.len == 5 && words[5] == 0xffff))) { + if (!inet_ntop4(src+12, tp, sizeof tmp - (tp - tmp))) + return (NULL); + tp += strlen(tp); + break; + } + tp += SPRINTF((tp, "%x", words[i])); + } + /* Was it a trailing run of 0x00's? */ + if (best.base != -1 && (best.base + best.len) == + (NS_IN6ADDRSZ / NS_INT16SZ)) + *tp++ = ':'; + *tp++ = '\0'; + + /* + * Check for overflow, copy, and we're done. + */ + if ((size_t)(tp - tmp) > size) { + errno = ENOSPC; + return (NULL); + } + strcpy(dst, tmp); + return (dst); +} + From 94c47dc6a85fa8c028382eb3b54e04f40d08590c Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Sun, 5 Aug 2012 02:31:27 +0200 Subject: [PATCH 156/252] nfs4: Add basic RPC level support for callbacks --- .../kernel/file_systems/nfs4/Connection.cpp | 172 +++++++++-- .../kernel/file_systems/nfs4/Connection.h | 46 ++- src/add-ons/kernel/file_systems/nfs4/Jamfile | 3 + .../kernel/file_systems/nfs4/NFS4Defs.h | 5 + .../kernel/file_systems/nfs4/RPCCallback.cpp | 24 ++ .../kernel/file_systems/nfs4/RPCCallback.h | 50 +++ .../file_systems/nfs4/RPCCallbackRequest.cpp | 71 +++++ .../file_systems/nfs4/RPCCallbackRequest.h | 82 +++++ .../file_systems/nfs4/RPCCallbackServer.cpp | 285 ++++++++++++++++++ .../file_systems/nfs4/RPCCallbackServer.h | 99 ++++++ .../kernel/file_systems/nfs4/RPCServer.cpp | 22 ++ .../kernel/file_systems/nfs4/RPCServer.h | 6 + .../file_systems/nfs4/RequestBuilder.cpp | 16 +- .../kernel/file_systems/nfs4/RequestBuilder.h | 2 +- .../file_systems/nfs4/kernel_interface.cpp | 9 + 15 files changed, 858 insertions(+), 34 deletions(-) create mode 100644 src/add-ons/kernel/file_systems/nfs4/RPCCallback.cpp create mode 100644 src/add-ons/kernel/file_systems/nfs4/RPCCallback.h create mode 100644 src/add-ons/kernel/file_systems/nfs4/RPCCallbackRequest.cpp create mode 100644 src/add-ons/kernel/file_systems/nfs4/RPCCallbackRequest.h create mode 100644 src/add-ons/kernel/file_systems/nfs4/RPCCallbackServer.cpp create mode 100644 src/add-ons/kernel/file_systems/nfs4/RPCCallbackServer.h diff --git a/src/add-ons/kernel/file_systems/nfs4/Connection.cpp b/src/add-ons/kernel/file_systems/nfs4/Connection.cpp index 6f14ed8e58..b9a5f0eb41 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Connection.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Connection.cpp @@ -129,6 +129,22 @@ ServerAddress::Port() const } +void +ServerAddress::SetPort(uint16 port) +{ + port = htons(port); + + switch (reinterpret_cast(&fAddress)->sa_family) { + case AF_INET: + reinterpret_cast(&fAddress)->sin_port = port; + break; + case AF_INET6: + reinterpret_cast(&fAddress)->sin6_port = port; + break; + } +} + + const void* ServerAddress::InAddr() const { @@ -147,7 +163,7 @@ ServerAddress::InAddr() const status_t ServerAddress::ResolveName(const char* name, ServerAddress* address) { - address->fProtocol = IPPROTO_UDP; + address->fProtocol = IPPROTO_TCP; // getaddrinfo() is very expensive when called from kernel, so we do not // want to call it unless there is no other choice. @@ -193,6 +209,20 @@ ServerAddress::ResolveName(const char* name, ServerAddress* address) Connection::Connection(const ServerAddress& address) + : + ConnectionBase(address) +{ +} + + +ConnectionListener::ConnectionListener(const ServerAddress& address) + : + ConnectionBase(address) +{ +} + + +ConnectionBase::ConnectionBase(const ServerAddress& address) : fWaitCancel(create_sem(0, NULL)), fSocket(-1), @@ -202,6 +232,7 @@ Connection::Connection(const ServerAddress& address) } + ConnectionStream::ConnectionStream(const ServerAddress& address) : Connection(address) @@ -216,7 +247,7 @@ ConnectionPacket::ConnectionPacket(const ServerAddress& address) } -Connection::~Connection() +ConnectionBase::~ConnectionBase() { if (fSocket != -1) close(fSocket); @@ -226,13 +257,13 @@ Connection::~Connection() status_t -Connection::GetLocalAddress(ServerAddress* address) +ConnectionBase::GetLocalAddress(ServerAddress* address) { address->fProtocol = fServerAddress.fProtocol; - socklen_t addressSize = fServerAddress.AddressSize(); - return getsockname(fSocket, - (struct sockaddr*)&address->fAddress, &addressSize); + socklen_t addressSize = sizeof(address->fAddress); + return getsockname(fSocket, (struct sockaddr*)&address->fAddress, + &addressSize); } @@ -409,20 +440,24 @@ ConnectionPacket::Receive(void** _buffer, uint32* _size) } +Connection* +Connection::CreateObject(const ServerAddress& address) +{ + switch (address.fProtocol) { + case IPPROTO_TCP: + return new(std::nothrow) ConnectionStream(address); + case IPPROTO_UDP: + return new(std::nothrow) ConnectionPacket(address); + default: + return NULL; + } +} + + status_t Connection::Connect(Connection **_connection, const ServerAddress& address) { - Connection* conn; - switch (address.fProtocol) { - case IPPROTO_TCP: - conn = new(std::nothrow) ConnectionStream(address); - break; - case IPPROTO_UDP: - conn = new(std::nothrow) ConnectionPacket(address); - break; - default: - return B_BAD_VALUE; - } + Connection* conn = CreateObject(address); if (conn == NULL) return B_NO_MEMORY; @@ -438,6 +473,21 @@ Connection::Connect(Connection **_connection, const ServerAddress& address) } +status_t +Connection::SetTo(Connection **_connection, int socket, + const ServerAddress& address) +{ + Connection* conn = CreateObject(address); + if (conn == NULL) + return B_NO_MEMORY; + conn->fSocket = socket; + + *_connection = conn; + + return B_OK; +} + + status_t Connection::Connect() { @@ -491,7 +541,7 @@ Connection::Reconnect() void -Connection::Disconnect() +ConnectionBase::Disconnect() { release_sem(fWaitCancel); @@ -499,3 +549,89 @@ Connection::Disconnect() fSocket = -1; } + +status_t +ConnectionListener::Listen(ConnectionListener** _listener, uint16 port) +{ + int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (sock < 0) + return errno; + + sockaddr_in addr; + memset(&addr, 0, sizeof(addr)); + addr.sin_len = sizeof(addr); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = INADDR_ANY; + addr.sin_port = htons(port); + if (bind(sock, (struct sockaddr*)&addr, sizeof(addr)) != B_OK) { + close(sock); + return errno; + } + + if (listen(sock, 5) != B_OK) { + close(sock); + return errno; + } + + ServerAddress address; + address.fProtocol = IPPROTO_TCP; + memset(&address.fAddress, 0, sizeof(address.fAddress)); + + ConnectionListener* listener; + listener = new(std::nothrow) ConnectionListener(address); + if (listener == NULL) { + close(sock); + return B_NO_MEMORY; + } + + listener->fSocket = sock; + + *_listener = listener; + + return B_OK; +} + + +status_t +ConnectionListener::AcceptConnection(Connection** _connection) +{ + object_wait_info object[2]; + object[0].object = fWaitCancel; + object[0].type = B_OBJECT_TYPE_SEMAPHORE; + object[0].events = B_EVENT_ACQUIRE_SEMAPHORE; + + object[1].object = fSocket; + object[1].type = B_OBJECT_TYPE_FD; + object[1].events = B_EVENT_READ; + + do { + status_t result = wait_for_objects(object, 2); + if (result < B_OK || + (object[0].events & B_EVENT_ACQUIRE_SEMAPHORE) != 0) { + return ECONNABORTED; + } else if ((object[1].events & B_EVENT_READ) == 0) + continue; + break; + } while (true); + + sockaddr_storage addr; + socklen_t length = sizeof(addr); + int sock = accept(fSocket, reinterpret_cast(&addr), &length); + if (sock < 0) + return errno; + + ServerAddress address; + address.fProtocol = IPPROTO_TCP; + address.fAddress = addr; + Connection* connection; + + status_t result = Connection::SetTo(&connection, sock, address); + if (result != B_OK) { + close(sock); + return result; + } + + *_connection = connection; + return B_OK; +} + diff --git a/src/add-ons/kernel/file_systems/nfs4/Connection.h b/src/add-ons/kernel/file_systems/nfs4/Connection.h index e16e2cdd8d..7b21564ad6 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Connection.h +++ b/src/add-ons/kernel/file_systems/nfs4/Connection.h @@ -31,31 +31,25 @@ struct ServerAddress { socklen_t AddressSize() const; + void SetPort(uint16 port); uint16 Port() const; + const void* InAddr() const; static status_t ResolveName(const char* name, ServerAddress* address); }; -class Connection { +class ConnectionBase { public: - static status_t Connect(Connection **connection, - const ServerAddress& address); - virtual ~Connection(); - - virtual status_t Send(const void* buffer, uint32 size) = 0; - virtual status_t Receive(void** buffer, uint32* size) = 0; + ConnectionBase(const ServerAddress& address); + virtual ~ConnectionBase(); status_t GetLocalAddress(ServerAddress* address); - status_t Reconnect(); void Disconnect(); protected: - Connection(const ServerAddress& address); - status_t Connect(); - sem_id fWaitCancel; int fSocket; mutex fSocketLock; @@ -63,6 +57,26 @@ protected: const ServerAddress fServerAddress; }; +class Connection : public ConnectionBase { +public: + static status_t Connect(Connection **connection, + const ServerAddress& address); + static status_t SetTo(Connection **connection, int socket, + const ServerAddress& address); + + virtual status_t Send(const void* buffer, uint32 size) = 0; + virtual status_t Receive(void** buffer, uint32* size) = 0; + + status_t Reconnect(); + +protected: + static Connection* CreateObject(const ServerAddress& address); + + Connection(const ServerAddress& address); + status_t Connect(); + +}; + class ConnectionStream : public Connection { public: ConnectionStream(const ServerAddress& address); @@ -79,5 +93,15 @@ public: virtual status_t Receive(void** buffer, uint32* size); }; +class ConnectionListener : public ConnectionBase { +public: + static status_t Listen(ConnectionListener** listener, uint16 port = 0); + + status_t AcceptConnection(Connection** connection); + +protected: + ConnectionListener(const ServerAddress& address); +}; + #endif // CONNECTION_H diff --git a/src/add-ons/kernel/file_systems/nfs4/Jamfile b/src/add-ons/kernel/file_systems/nfs4/Jamfile index 16a0306a88..abe0a46688 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Jamfile +++ b/src/add-ons/kernel/file_systems/nfs4/Jamfile @@ -26,6 +26,9 @@ KernelAddon nfs4 : RootInode.cpp RPCAuth.cpp RPCCall.cpp + RPCCallback.cpp + RPCCallbackRequest.cpp + RPCCallbackServer.cpp RPCReply.cpp RPCServer.cpp XDR.cpp diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h index e9775aaa8d..c0abd7b0fd 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h @@ -20,6 +20,11 @@ enum Procedure { ProcCompound = 1 }; +enum CallbackProcedure { + CallbackProcNull = 0, + CallbackProcCompound = 1 +}; + enum Opcode { OpAccess = 3, OpClose = 4, diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCCallback.cpp b/src/add-ons/kernel/file_systems/nfs4/RPCCallback.cpp new file mode 100644 index 0000000000..70da61c58e --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/RPCCallback.cpp @@ -0,0 +1,24 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ + + +#include "RPCCallback.h" + +#include "RPCCallbackRequest.h" + + +using namespace RPC; + + +status_t +Callback::EnqueueRequest(CallbackRequest* request, Connection* connection) +{ + dprintf("GOT A CALLBACK REQUEST %x\n", (int)request->XID()); + return B_OK; +} + diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCCallback.h b/src/add-ons/kernel/file_systems/nfs4/RPCCallback.h new file mode 100644 index 0000000000..66d60ac116 --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/RPCCallback.h @@ -0,0 +1,50 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ +#ifndef RPCCALLBACK_H +#define RPCCALLBACK_H + + +#include "Connection.h" + + +namespace RPC { + +class CallbackRequest; + +class Callback { +public: + inline void SetID(int32 id); + inline int32 ID(); + + status_t EnqueueRequest(CallbackRequest* request, + Connection* connection); + +private: + int32 fID; +}; + + +inline void +Callback::SetID(int32 id) +{ + fID = id; +} + + +inline int32 +Callback::ID() +{ + return fID; +} + + +} // namespace RPC + + +#endif // RPCCALLBACK_H + diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCCallbackRequest.cpp b/src/add-ons/kernel/file_systems/nfs4/RPCCallbackRequest.cpp new file mode 100644 index 0000000000..39788b1ca0 --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/RPCCallbackRequest.cpp @@ -0,0 +1,71 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ + + +#include "RPCCallbackRequest.h" + +#include + +#include "NFS4Defs.h" + + +using namespace RPC; + +enum { + CALL = 0 +}; + +#define VERSION 2 + +enum { + PROGRAM_NFS_CB = 0x40000000 +}; + +#define NFS_VERSION 4 + + +CallbackRequest::CallbackRequest(void *buffer, int size) + : + fError(B_BAD_VALUE), + fStream(buffer, size), + fBuffer(buffer) +{ + fXID = fStream.GetUInt(); + + if (fStream.GetUInt() != CALL) + return; + + if (fStream.GetUInt() != VERSION) + return; + + if (fStream.GetUInt() != PROGRAM_NFS_CB) + return; + + fProcedure = fStream.GetUInt(); + + fStream.GetOpaque(NULL); + fStream.GetOpaque(NULL); + + if (fProcedure == CallbackProcCompound) { + fStream.GetOpaque(NULL); // TODO: tag may be important + if (fStream.GetUInt() != 0) + return; + + fID = fStream.GetUInt(); + } + + fError = B_OK; +} + + +CallbackRequest::~CallbackRequest() +{ + free(fBuffer); +} + + diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCCallbackRequest.h b/src/add-ons/kernel/file_systems/nfs4/RPCCallbackRequest.h new file mode 100644 index 0000000000..28b822e234 --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/RPCCallbackRequest.h @@ -0,0 +1,82 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ +#ifndef RPCCALLBACKREQUEST_H +#define RPCCALLBACKREQUEST_H + + +#include "XDR.h" + + +namespace RPC { + +class CallbackRequest { +public: + CallbackRequest(void *buffer, int size); + ~CallbackRequest(); + + inline uint32 XID(); + inline uint32 ID(); + + inline uint32 Procedure(); + + inline status_t Error(); + inline XDR::ReadStream& Stream(); + +private: + uint32 fXID; + uint32 fID; + + uint32 fProcedure; + + status_t fError; + + XDR::ReadStream fStream; + void* fBuffer; +}; + + +inline uint32 +CallbackRequest::XID() +{ + return fXID; +} + + +inline uint32 +CallbackRequest::ID() +{ + return fID; +} + + +inline uint32 +CallbackRequest::Procedure() +{ + return fProcedure; +} + + +inline status_t +CallbackRequest::Error() +{ + return fError; +} + + +inline XDR::ReadStream& +CallbackRequest::Stream() +{ + return fStream; +} + + +} // namespace RPC + + +#endif // RPCCALLBACKREQUEST_H + diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCCallbackServer.cpp b/src/add-ons/kernel/file_systems/nfs4/RPCCallbackServer.cpp new file mode 100644 index 0000000000..837557e947 --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/RPCCallbackServer.cpp @@ -0,0 +1,285 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ + + +#include "RPCCallbackServer.h" + +#include "NFS4Defs.h" +#include "RPCCallback.h" +#include "RPCCallbackRequest.h" + + +using namespace RPC; + + +CallbackServer* gRPCCallbackServer = NULL; + + +CallbackServer::CallbackServer() + : + fConnectionList(NULL), + fListener(NULL), + fThreadRunning(false), + fCallbackArray(NULL), + fArraySize(0), + fFreeSlot(-1) +{ + mutex_init(&fConnectionLock, NULL); + mutex_init(&fThreadLock, NULL); + rw_lock_init(&fArrayLock, NULL); +} + + +CallbackServer::~CallbackServer() +{ + StopServer(); + + free(fCallbackArray); + rw_lock_destroy(&fArrayLock); + mutex_destroy(&fThreadLock); + mutex_destroy(&fConnectionLock); +} + + +status_t +CallbackServer::RegisterCallback(Callback* callback) +{ + status_t result = StartServer(); + if (result != B_OK) + return result; + + WriteLocker _(fArrayLock); + if (fFreeSlot == -1) { + uint32 newSize = max_c(fArraySize * 2, 4); + uint32 size = newSize * sizeof(CallbackSlot); + CallbackSlot* array = reinterpret_cast(malloc(size)); + if (array == NULL) + return B_NO_MEMORY; + + if (fCallbackArray != NULL) + memcpy(array, fCallbackArray, fArraySize * sizeof(CallbackSlot)); + + for (uint32 i = fArraySize; i < newSize; i++) + array[i].fNext = i + 1; + + array[fArraySize * 2 - 1].fNext = -1; + + fCallbackArray = array; + fFreeSlot = fArraySize; + fArraySize = newSize; + } + + int32 id = fFreeSlot; + fFreeSlot = fCallbackArray[id].fNext; + + fCallbackArray[id].fCallback = callback; + callback->SetID(id); + + return B_OK; +} + + +status_t +CallbackServer::UnregisterCallback(Callback* callback) +{ + int32 id = callback->ID(); + + WriteLocker _(fArrayLock); + fCallbackArray[id].fNext = fFreeSlot; + fFreeSlot = id; + + return B_OK; +} + + +status_t +CallbackServer::StartServer() +{ + MutexLocker _(fThreadLock); + if (fThreadRunning) + return B_OK; + + status_t result = ConnectionListener::Listen(&fListener); + if (result != B_OK) + return result; + + fThread = spawn_kernel_thread(&CallbackServer::ListenerThreadLauncher, + "NFSv4 Callback Listener", B_NORMAL_PRIORITY, this); + if (fThread < B_OK) + return fThread; + + fThreadRunning = true; + + result = resume_thread(fThread); + if (result != B_OK) { + kill_thread(fThread); + fThreadRunning = false; + return result; + } + + return B_OK; +} + + +status_t +CallbackServer::StopServer() +{ + MutexLocker _(&fThreadLock); + if (!fThreadRunning) + return B_OK; + + fListener->Disconnect(); + status_t result; + wait_for_thread(fThread, &result); + + MutexLocker locker(fConnectionLock); + while (fConnectionList != NULL) { + ConnectionEntry* entry = fConnectionList; + fConnectionList = entry->fNext; + entry->fConnection->Disconnect(); + delete entry->fConnection; + delete entry; + } + + delete fListener; + + fThreadRunning = false; + return B_OK; +} + + +status_t +CallbackServer::NewConnection(Connection* connection) +{ + ConnectionEntry* entry = new ConnectionEntry; + entry->fConnection = connection; + entry->fPrev = NULL; + + MutexLocker locker(fConnectionLock); + entry->fNext = fConnectionList; + fConnectionList = entry; + locker.Unlock(); + + void** arguments = reinterpret_cast(malloc(sizeof(void*) * 2)); + if (arguments == NULL) + return B_NO_MEMORY; + + arguments[0] = this; + arguments[1] = connection; + + thread_id thread; + thread = spawn_kernel_thread(&CallbackServer::ConnectionThreadLauncher, + "NFSv4 Callback Connection", B_NORMAL_PRIORITY, arguments); + if (thread < B_OK) { + free(arguments); + return thread; + } + + status_t result = resume_thread(thread); + if (result != B_OK) { + kill_thread(thread); + free(arguments); + return result; + } + + return B_OK; +} + + +status_t +CallbackServer::ReleaseConnection(ConnectionEntry* entry) +{ + MutexLocker _(fConnectionLock); + if (entry->fNext != NULL) + entry->fNext->fPrev = entry->fPrev; + if (entry->fPrev != NULL) + entry->fPrev->fNext = entry->fNext; + else + fConnectionList = entry->fNext; + + delete entry->fConnection; + delete entry; + return B_OK; +} + + +status_t +CallbackServer::ConnectionThreadLauncher(void* object) +{ + void** objects = reinterpret_cast(object); + CallbackServer* server = reinterpret_cast(objects[0]); + ConnectionEntry* entry = reinterpret_cast(objects[1]); + free(objects); + + return server->ConnectionThread(entry); +} + + +status_t +CallbackServer::ConnectionThread(ConnectionEntry* entry) +{ + Connection* connection = entry->fConnection; + dprintf("NEW CONNECTION\n"); + while (fThreadRunning) { + uint32 size; + void* buffer; + status_t result = connection->Receive(&buffer, &size); + if (result != B_OK) { + ReleaseConnection(entry); + return result; + } + + CallbackRequest* request = new CallbackRequest(buffer, size); + if (request == NULL || request->Error() != B_OK) { + free(buffer); + continue; + } + + switch (request->Procedure()) { + case CallbackProcCompound: + GetCallback(request->ID())->EnqueueRequest(request, connection); + break; + + case CallbackProcNull: + dprintf("GOT CB_NULL %x\n", (int)request->XID()); + + default: + free(buffer); + } + } + + return B_OK; +} + + +status_t +CallbackServer::ListenerThreadLauncher(void* object) +{ + CallbackServer* server = reinterpret_cast(object); + return server->ListenerThread(); +} + + +status_t +CallbackServer::ListenerThread() +{ + while (fThreadRunning) { + Connection* connection; + status_t result = fListener->AcceptConnection(&connection); + if (result != B_OK) { + fThreadRunning = false; + return result; + } + result = NewConnection(connection); + if (result != B_OK) + delete connection; + } + + return B_OK; +} + diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCCallbackServer.h b/src/add-ons/kernel/file_systems/nfs4/RPCCallbackServer.h new file mode 100644 index 0000000000..9b22f20e05 --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/RPCCallbackServer.h @@ -0,0 +1,99 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ +#ifndef RPCCALLBACKSERVER_H +#define RPCCALLBACKSERVER_H + + +#include + +#include "Connection.h" + + +namespace RPC { + +class Callback; + +struct ConnectionEntry { + Connection* fConnection; + ConnectionEntry* fNext; + ConnectionEntry* fPrev; +}; + +union CallbackSlot { + Callback* fCallback; + int32 fNext; +}; + +class CallbackServer { +public: + CallbackServer(); + ~CallbackServer(); + + status_t RegisterCallback(Callback* callback); + status_t UnregisterCallback(Callback* callback); + + inline ServerAddress LocalID(); + +protected: + status_t StartServer(); + status_t StopServer(); + + status_t NewConnection(Connection* connection); + status_t ReleaseConnection(ConnectionEntry* entry); + + static status_t ListenerThreadLauncher(void* object); + status_t ListenerThread(); + + static status_t ConnectionThreadLauncher(void* object); + status_t ConnectionThread(ConnectionEntry* entry); + + inline Callback* GetCallback(int32 id); + +private: + mutex fConnectionLock; + ConnectionEntry* fConnectionList; + ConnectionListener* fListener; + + mutex fThreadLock; + thread_id fThread; + bool fThreadRunning; + + rw_lock fArrayLock; + CallbackSlot* fCallbackArray; + uint32 fArraySize; + int32 fFreeSlot; +}; + + +inline ServerAddress +CallbackServer::LocalID() +{ + ServerAddress address; + fListener->GetLocalAddress(&address); + return address; +} + + +inline Callback* +CallbackServer::GetCallback(int32 id) +{ + ReadLocker _(fArrayLock); + if (id >= 0 && static_cast(id) < fArraySize) + return fCallbackArray[id].fCallback; + return NULL; +} + + +} // namespace RPC + + +extern RPC::CallbackServer* gRPCCallbackServer; + + +#endif // RPCCALLBACKSERVER_H + diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp b/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp index e13a36e276..fce6f5aa3b 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp @@ -13,6 +13,7 @@ #include +#include "RPCCallbackServer.h" #include "RPCReply.h" @@ -77,14 +78,22 @@ Server::Server(Connection* connection, ServerAddress* address) fConnection(connection), fAddress(address), fPrivateData(NULL), + fCallback(NULL), fXID(rand() << 1) { + mutex_init(&fCallbackLock, NULL); + _StartListening(); } Server::~Server() { + if (fCallback != NULL) + gRPCCallbackServer->UnregisterCallback(fCallback); + delete fCallback; + mutex_destroy(&fCallbackLock); + delete fPrivateData; fThreadCancel = true; @@ -214,6 +223,19 @@ Server::Repair() } +Callback* +Server::GetCallback() +{ + MutexLocker _(fCallbackLock); + if (fCallback == NULL) { + fCallback = new Callback; + gRPCCallbackServer->RegisterCallback(fCallback); + } + + return fCallback; +} + + uint32 Server::_GetXID() { diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCServer.h b/src/add-ons/kernel/file_systems/nfs4/RPCServer.h index 3a954b35cd..ddcb80e423 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RPCServer.h +++ b/src/add-ons/kernel/file_systems/nfs4/RPCServer.h @@ -14,6 +14,7 @@ #include "Connection.h" #include "RPCCall.h" +#include "RPCCallback.h" #include "RPCReply.h" @@ -76,6 +77,8 @@ public: inline ProgramData* PrivateData(); inline void SetPrivateData(ProgramData* privateData); + Callback* GetCallback(); + private: inline uint32 _GetXID(); @@ -94,6 +97,9 @@ private: ProgramData* fPrivateData; + mutex fCallbackLock; + Callback* fCallback; + vint32 fXID; static const bigtime_t kWaitTime = 1000000; }; diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp index 9c44aa2815..c9d2408503 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp @@ -13,6 +13,8 @@ #include #include "Cookie.h" +#include "RPCCallback.h" +#include "RPCCallbackServer.h" RequestBuilder::RequestBuilder(Procedure proc) @@ -620,7 +622,7 @@ RequestBuilder::SetAttr(const uint32* id, uint32 stateSeq, AttrValue* attr, status_t -RequestBuilder::SetClientID(const RPC::Server* server) +RequestBuilder::SetClientID(RPC::Server* server) { if (fProcedure != ProcCompound) return B_BAD_VALUE; @@ -638,15 +640,21 @@ RequestBuilder::SetClientID(const RPC::Server* server) fRequest->Stream().AddUInt(0x40000000); - ServerAddress local = server->LocalID(); + uint32 id = server->GetCallback()->ID(); + + ServerAddress local = gRPCCallbackServer->LocalID(); + ServerAddress servAddr = server->LocalID(); + servAddr.SetPort(local.Port()); + fRequest->Stream().AddString(local.ProtocolString()); - char* uAddr = local.UniversalAddress(); + + char* uAddr = servAddr.UniversalAddress(); if (uAddr == NULL) return B_NO_MEMORY; fRequest->Stream().AddString(uAddr); free(uAddr); - fRequest->Stream().AddUInt(0); + fRequest->Stream().AddUInt(id); fOpCount++; diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h index b3b7998955..a8f2d7618d 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h @@ -69,7 +69,7 @@ public: status_t SaveFH(); status_t SetAttr(const uint32* id, uint32 stateSeq, AttrValue* attr, uint32 count); - status_t SetClientID(const RPC::Server* server); + status_t SetClientID(RPC::Server* server); status_t SetClientIDConfirm(uint64 id, uint64 ver); status_t Verify(AttrValue* attr, uint32 count); status_t Write(const uint32* id, uint32 stateSeq, 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 cc58c5593b..95b8bd87eb 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -20,6 +20,7 @@ #include "RequestBuilder.h" #include "ReplyInterpreter.h" #include "RootInode.h" +#include "RPCCallbackServer.h" #include "RPCServer.h" @@ -637,6 +638,13 @@ nfs4_init() return B_NO_MEMORY; } + gRPCCallbackServer = new(std::nothrow) RPC::CallbackServer; + if (gRPCCallbackServer == NULL) { + delete gRPCServerManager; + delete gIdMapper; + return B_NO_MEMORY; + } + return B_OK; } @@ -646,6 +654,7 @@ nfs4_uninit() { dprintf("NFS4 Uninit\n"); + delete gRPCCallbackServer; delete gIdMapper; delete gRPCServerManager; From 8019eaf184c1cadcf0ef6625e439851d0133de24 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Sun, 5 Aug 2012 03:10:38 +0200 Subject: [PATCH 157/252] nfs4: Several minor fixes --- src/add-ons/kernel/file_systems/nfs4/Connection.cpp | 6 ++---- src/add-ons/kernel/file_systems/nfs4/RPCCallbackRequest.cpp | 5 ++++- src/add-ons/kernel/file_systems/nfs4/RPCCallbackServer.cpp | 4 ++-- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Connection.cpp b/src/add-ons/kernel/file_systems/nfs4/Connection.cpp index b9a5f0eb41..25ed74b9b4 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Connection.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Connection.cpp @@ -593,7 +593,7 @@ ConnectionListener::Listen(ConnectionListener** _listener, uint16 port) status_t -ConnectionListener::AcceptConnection(Connection** _connection) +ConnectionListener::AcceptConnection(Connection** connection) { object_wait_info object[2]; object[0].object = fWaitCancel; @@ -623,15 +623,13 @@ ConnectionListener::AcceptConnection(Connection** _connection) ServerAddress address; address.fProtocol = IPPROTO_TCP; address.fAddress = addr; - Connection* connection; - status_t result = Connection::SetTo(&connection, sock, address); + status_t result = Connection::SetTo(connection, sock, address); if (result != B_OK) { close(sock); return result; } - *_connection = connection; return B_OK; } diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCCallbackRequest.cpp b/src/add-ons/kernel/file_systems/nfs4/RPCCallbackRequest.cpp index 39788b1ca0..c4841127ad 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RPCCallbackRequest.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RPCCallbackRequest.cpp @@ -26,7 +26,7 @@ enum { PROGRAM_NFS_CB = 0x40000000 }; -#define NFS_VERSION 4 +#define NFS_CB_VERSION 1 CallbackRequest::CallbackRequest(void *buffer, int size) @@ -46,6 +46,9 @@ CallbackRequest::CallbackRequest(void *buffer, int size) if (fStream.GetUInt() != PROGRAM_NFS_CB) return; + if (fStream.GetUInt() != NFS_CB_VERSION) + return; + fProcedure = fStream.GetUInt(); fStream.GetOpaque(NULL); diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCCallbackServer.cpp b/src/add-ons/kernel/file_systems/nfs4/RPCCallbackServer.cpp index 837557e947..5ff83f6ffc 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RPCCallbackServer.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RPCCallbackServer.cpp @@ -170,7 +170,7 @@ CallbackServer::NewConnection(Connection* connection) return B_NO_MEMORY; arguments[0] = this; - arguments[1] = connection; + arguments[1] = entry; thread_id thread; thread = spawn_kernel_thread(&CallbackServer::ConnectionThreadLauncher, @@ -224,7 +224,7 @@ status_t CallbackServer::ConnectionThread(ConnectionEntry* entry) { Connection* connection = entry->fConnection; - dprintf("NEW CONNECTION\n"); + while (fThreadRunning) { uint32 size; void* buffer; From feb15cc63ce6f32dc73e8322c165266d4a11b149 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Sun, 5 Aug 2012 03:50:30 +0200 Subject: [PATCH 158/252] nfs4: Reply to incorrect and CB_NULL callback requests --- src/add-ons/kernel/file_systems/nfs4/Jamfile | 1 + .../kernel/file_systems/nfs4/RPCAuth.cpp | 2 + .../kernel/file_systems/nfs4/RPCAuth.h | 5 -- .../kernel/file_systems/nfs4/RPCCall.cpp | 14 +---- .../file_systems/nfs4/RPCCallbackReply.cpp | 49 +++++++++++++++ .../file_systems/nfs4/RPCCallbackReply.h | 42 +++++++++++++ .../file_systems/nfs4/RPCCallbackRequest.cpp | 30 ++++----- .../file_systems/nfs4/RPCCallbackRequest.h | 11 ++++ .../file_systems/nfs4/RPCCallbackServer.cpp | 19 +++++- .../kernel/file_systems/nfs4/RPCDefs.h | 61 +++++++++++++++++++ .../kernel/file_systems/nfs4/RPCReply.cpp | 25 +------- 11 files changed, 201 insertions(+), 58 deletions(-) create mode 100644 src/add-ons/kernel/file_systems/nfs4/RPCCallbackReply.cpp create mode 100644 src/add-ons/kernel/file_systems/nfs4/RPCCallbackReply.h create mode 100644 src/add-ons/kernel/file_systems/nfs4/RPCDefs.h diff --git a/src/add-ons/kernel/file_systems/nfs4/Jamfile b/src/add-ons/kernel/file_systems/nfs4/Jamfile index abe0a46688..b6aeed821e 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Jamfile +++ b/src/add-ons/kernel/file_systems/nfs4/Jamfile @@ -27,6 +27,7 @@ KernelAddon nfs4 : RPCAuth.cpp RPCCall.cpp RPCCallback.cpp + RPCCallbackReply.cpp RPCCallbackRequest.cpp RPCCallbackServer.cpp RPCReply.cpp diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCAuth.cpp b/src/add-ons/kernel/file_systems/nfs4/RPCAuth.cpp index e9ce2aa365..b10f2abba0 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RPCAuth.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RPCAuth.cpp @@ -16,6 +16,8 @@ #include #include +#include "RPCDefs.h" + using namespace RPC; diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCAuth.h b/src/add-ons/kernel/file_systems/nfs4/RPCAuth.h index 81a127f3ab..d45a7cf460 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RPCAuth.h +++ b/src/add-ons/kernel/file_systems/nfs4/RPCAuth.h @@ -14,11 +14,6 @@ namespace RPC { -enum auth_flavour { - AUTH_NONE = 0, - AUTH_SYS = 1 -}; - class Auth { public: inline const XDR::WriteStream& Stream() const; diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCCall.cpp b/src/add-ons/kernel/file_systems/nfs4/RPCCall.cpp index 323e7f1f2e..fcc3124803 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RPCCall.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RPCCall.cpp @@ -11,21 +11,11 @@ #include +#include "RPCDefs.h" + using namespace RPC; -enum { - CALL = 0 -}; - -#define VERSION 2 - -enum { - PROGRAM_NFS = 100003 -}; - -#define NFS_VERSION 4 - Call::Call() { diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCCallbackReply.cpp b/src/add-ons/kernel/file_systems/nfs4/RPCCallbackReply.cpp new file mode 100644 index 0000000000..595bb0989f --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/RPCCallbackReply.cpp @@ -0,0 +1,49 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ + + +#include "RPCCallbackReply.h" + +#include + +#include "RPCDefs.h" + + +using namespace RPC; + + +CallbackReply::CallbackReply() +{ +} + + +CallbackReply* +CallbackReply::Create(uint32 xid, AcceptStat rpcError) +{ + CallbackReply* reply = new(std::nothrow) CallbackReply; + if (reply == NULL) + return NULL; + + reply->fStream.AddUInt(xid); + + reply->fStream.AddInt(REPLY); + reply->fStream.AddUInt(MSG_ACCEPTED); + + reply->fStream.AddInt(AUTH_NONE); + reply->fStream.AddOpaque(NULL, 0); + + reply->fStream.AddUInt(rpcError); + + return reply; +} + + +CallbackReply::~CallbackReply() +{ +} + diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCCallbackReply.h b/src/add-ons/kernel/file_systems/nfs4/RPCCallbackReply.h new file mode 100644 index 0000000000..485d5fa8a8 --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/RPCCallbackReply.h @@ -0,0 +1,42 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ +#ifndef RPCCALLBACKREPLY_H +#define RPCCALLBACKREPLY_H + + +#include "RPCDefs.h" +#include "XDR.h" + + +namespace RPC { + +class CallbackReply { +public: + static CallbackReply* Create(uint32 xid, + AcceptStat rpcError = SUCCESS); + ~CallbackReply(); + + inline XDR::WriteStream& Stream(); + +private: + CallbackReply(); + + XDR::WriteStream fStream; +}; + + +inline XDR::WriteStream& +CallbackReply::Stream() +{ + return fStream; +} + +} // namespace RPC + + +#endif // RPCCALLBACKREPLY_H diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCCallbackRequest.cpp b/src/add-ons/kernel/file_systems/nfs4/RPCCallbackRequest.cpp index c4841127ad..4b10efb928 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RPCCallbackRequest.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RPCCallbackRequest.cpp @@ -12,26 +12,16 @@ #include #include "NFS4Defs.h" +#include "RPCDefs.h" using namespace RPC; -enum { - CALL = 0 -}; - -#define VERSION 2 - -enum { - PROGRAM_NFS_CB = 0x40000000 -}; - -#define NFS_CB_VERSION 1 - CallbackRequest::CallbackRequest(void *buffer, int size) : fError(B_BAD_VALUE), + fRPCError(GARBAGE_ARGS), fStream(buffer, size), fBuffer(buffer) { @@ -43,11 +33,15 @@ CallbackRequest::CallbackRequest(void *buffer, int size) if (fStream.GetUInt() != VERSION) return; - if (fStream.GetUInt() != PROGRAM_NFS_CB) + if (fStream.GetUInt() != PROGRAM_NFS_CB) { + fRPCError = PROG_UNAVAIL; return; + } - if (fStream.GetUInt() != NFS_CB_VERSION) + if (fStream.GetUInt() != NFS_CB_VERSION) { + fRPCError = PROG_MISMATCH; return; + } fProcedure = fStream.GetUInt(); @@ -60,9 +54,11 @@ CallbackRequest::CallbackRequest(void *buffer, int size) return; fID = fStream.GetUInt(); - } - - fError = B_OK; + } else if (fProcedure == CallbackProcNull) { + fRPCError = SUCCESS; + fError = B_OK; + } else + fRPCError = PROC_UNAVAIL; } diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCCallbackRequest.h b/src/add-ons/kernel/file_systems/nfs4/RPCCallbackRequest.h index 28b822e234..01518f3b6c 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RPCCallbackRequest.h +++ b/src/add-ons/kernel/file_systems/nfs4/RPCCallbackRequest.h @@ -9,6 +9,7 @@ #define RPCCALLBACKREQUEST_H +#include "RPCDefs.h" #include "XDR.h" @@ -25,6 +26,8 @@ public: inline uint32 Procedure(); inline status_t Error(); + inline AcceptStat RPCError(); + inline XDR::ReadStream& Stream(); private: @@ -34,6 +37,7 @@ private: uint32 fProcedure; status_t fError; + AcceptStat fRPCError; XDR::ReadStream fStream; void* fBuffer; @@ -68,6 +72,13 @@ CallbackRequest::Error() } +inline AcceptStat +CallbackRequest::RPCError() +{ + return fRPCError; +} + + inline XDR::ReadStream& CallbackRequest::Stream() { diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCCallbackServer.cpp b/src/add-ons/kernel/file_systems/nfs4/RPCCallbackServer.cpp index 5ff83f6ffc..651ccc5426 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RPCCallbackServer.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RPCCallbackServer.cpp @@ -11,6 +11,7 @@ #include "NFS4Defs.h" #include "RPCCallback.h" +#include "RPCCallbackReply.h" #include "RPCCallbackRequest.h" @@ -224,6 +225,7 @@ status_t CallbackServer::ConnectionThread(ConnectionEntry* entry) { Connection* connection = entry->fConnection; + CallbackReply* reply; while (fThreadRunning) { uint32 size; @@ -238,15 +240,30 @@ CallbackServer::ConnectionThread(ConnectionEntry* entry) if (request == NULL || request->Error() != B_OK) { free(buffer); continue; + } else if (request != NULL) { + reply = CallbackReply::Create(request->XID(), request->RPCError()); + if (reply != NULL) { + connection->Send(reply->Stream().Buffer(), + reply->Stream().Size()); + delete reply; + } + free(buffer); + continue; } + switch (request->Procedure()) { case CallbackProcCompound: GetCallback(request->ID())->EnqueueRequest(request, connection); break; case CallbackProcNull: - dprintf("GOT CB_NULL %x\n", (int)request->XID()); + reply = CallbackReply::Create(request->XID()); + if (reply != NULL) { + connection->Send(reply->Stream().Buffer(), + reply->Stream().Size()); + delete reply; + } default: free(buffer); diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCDefs.h b/src/add-ons/kernel/file_systems/nfs4/RPCDefs.h new file mode 100644 index 0000000000..bd551a69b5 --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/RPCDefs.h @@ -0,0 +1,61 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ +#ifndef RPCDEFS_H +#define RPCDEFS_H + + +namespace RPC { + +enum { + VERSION = 2 +}; + +enum { + PROGRAM_NFS = 100003, + PROGRAM_NFS_CB = 0x40000000 +}; + +enum { + NFS_VERSION = 4, + NFS_CB_VERSION = 1 +}; + +enum { + CALL = 0, + REPLY = 1 +}; + +enum { + MSG_ACCEPTED = 0, + MSG_DENIED = 1 +}; + +enum AcceptStat { + SUCCESS = 0, /* RPC executed successfully */ + PROG_UNAVAIL = 1, /* remote hasn't exported program */ + PROG_MISMATCH = 2, /* remote can't support version # */ + PROC_UNAVAIL = 3, /* program can't support procedure */ + GARBAGE_ARGS = 4, /* procedure can't decode params */ + SYSTEM_ERR = 5 /* e.g. memory allocation failure */ +}; + +enum RejectStat { + RPC_MISMATCH = 0, /* RPC version number != 2 */ + AUTH_ERROR = 1 /* remote can't authenticate caller */ +}; + +enum AuthFlavour { + AUTH_NONE = 0, + AUTH_SYS = 1 +}; + +} // namespace RPC + + +#endif // RPCDEFS_H + diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCReply.cpp b/src/add-ons/kernel/file_systems/nfs4/RPCReply.cpp index 3dfa899069..3f61357e09 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RPCReply.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RPCReply.cpp @@ -11,32 +11,11 @@ #include +#include "RPCDefs.h" + using namespace RPC; -enum { - REPLY = 1 -}; - -enum { - MSG_ACCEPTED = 0, - MSG_DENIED = 1 -}; - -enum accept_stat { - SUCCESS = 0, /* RPC executed successfully */ - PROG_UNAVAIL = 1, /* remote hasn't exported program */ - PROG_MISMATCH = 2, /* remote can't support version # */ - PROC_UNAVAIL = 3, /* program can't support procedure */ - GARBAGE_ARGS = 4, /* procedure can't decode params */ - SYSTEM_ERR = 5 /* e.g. memory allocation failure */ -}; - -enum reject_stat { - RPC_MISMATCH = 0, /* RPC version number != 2 */ - AUTH_ERROR = 1 /* remote can't authenticate caller */ -}; - Reply::Reply(void *buffer, int size) : From 5a9212d612306df5df3ca1b2f0eb0112c57e2def Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Sun, 5 Aug 2012 15:44:16 +0200 Subject: [PATCH 159/252] nfs4: NFS4Object::HandleErrors needs OpenState or OpenFileCookie object --- .../kernel/file_systems/nfs4/NFS4Inode.cpp | 6 +++--- .../kernel/file_systems/nfs4/NFS4Object.cpp | 15 ++++++++++++--- src/add-ons/kernel/file_systems/nfs4/NFS4Object.h | 2 +- .../kernel/file_systems/nfs4/OpenState.cpp | 2 +- 4 files changed, 17 insertions(+), 8 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp index a95c3b9700..cb8988178f 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp @@ -539,7 +539,7 @@ NFS4Inode::OpenFile(OpenState* state, int mode) ReplyInterpreter& reply = request.Reply(); - if (HandleErrors(reply.NFS4Error(), serv)) + if (HandleErrors(reply.NFS4Error(), serv, NULL, state)) continue; // Verify if the file we want to open is the file this Inode @@ -592,7 +592,7 @@ NFS4Inode::ReadFile(OpenFileCookie* cookie, OpenState* state, uint64 position, ReplyInterpreter& reply = request.Reply(); - if (HandleErrors(reply.NFS4Error(), serv, cookie)) + if (HandleErrors(reply.NFS4Error(), serv, cookie, state)) continue; reply.PutFH(); @@ -625,7 +625,7 @@ NFS4Inode::WriteFile(OpenFileCookie* cookie, OpenState* state, uint64 position, ReplyInterpreter& reply = request.Reply(); - if (HandleErrors(reply.NFS4Error(), serv, cookie)) + if (HandleErrors(reply.NFS4Error(), serv, cookie, state)) continue; reply.PutFH(); diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp index e5db3e618c..73c5e3a5bb 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp @@ -15,7 +15,7 @@ bool NFS4Object::HandleErrors(uint32 nfs4Error, RPC::Server* serv, - OpenFileCookie* cookie) + OpenFileCookie* cookie, OpenState* state) { uint32 leaseTime; @@ -62,8 +62,14 @@ NFS4Object::HandleErrors(uint32 nfs4Error, RPC::Server* serv, // server has rebooted, reclaim share and try again case NFS4ERR_STALE_CLIENTID: case NFS4ERR_STALE_STATEID: - fFileSystem->NFSServer()->ServerRebooted(cookie->fClientID); - return true; + if (cookie != NULL) { + fFileSystem->NFSServer()->ServerRebooted(cookie->fClientID); + return true; + } else if (state != NULL) { + fFileSystem->NFSServer()->ServerRebooted(state->fClientID); + return true; + } + return false; // FileHandle has expired case NFS4ERR_FHEXPIRED: @@ -82,6 +88,9 @@ NFS4Object::HandleErrors(uint32 nfs4Error, RPC::Server* serv, if (cookie != NULL) { fFileSystem->NFSServer()->ClientId(cookie->fClientID, true); return true; + } else if (state != NULL) { + fFileSystem->NFSServer()->ClientId(state->fClientID, true); + return true; } return false; diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Object.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Object.h index 7ffcf4b9a1..79df6f1337 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Object.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Object.h @@ -19,7 +19,7 @@ class OpenState; class NFS4Object { public: bool HandleErrors(uint32 nfs4Error, RPC::Server* serv, - OpenFileCookie* cookie = NULL); + OpenFileCookie* cookie = NULL, OpenState* state = NULL); status_t ConfirmOpen(const FileHandle& fileHandle, OpenState* state); diff --git a/src/add-ons/kernel/file_systems/nfs4/OpenState.cpp b/src/add-ons/kernel/file_systems/nfs4/OpenState.cpp index 26a4df52e5..4959199340 100644 --- a/src/add-ons/kernel/file_systems/nfs4/OpenState.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/OpenState.cpp @@ -101,7 +101,7 @@ OpenState::Close() ReplyInterpreter& reply = request.Reply(); - if (HandleErrors(reply.NFS4Error(), serv)) + if (HandleErrors(reply.NFS4Error(), serv, NULL, this)) continue; reply.PutFH(); From 990922235b448d860c0dbcf596c21bfdbeab8831 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Sun, 5 Aug 2012 19:37:58 +0200 Subject: [PATCH 160/252] nfs4: Use global open owner, check whether delegation was granted --- .../kernel/file_systems/nfs4/Connection.cpp | 11 ++-- .../kernel/file_systems/nfs4/FileSystem.cpp | 7 +++ .../kernel/file_systems/nfs4/FileSystem.h | 32 ++++++++++ .../kernel/file_systems/nfs4/NFS4Defs.h | 21 +++++++ .../kernel/file_systems/nfs4/NFS4Inode.cpp | 62 +++++++++++++------ .../kernel/file_systems/nfs4/NFS4Object.cpp | 9 ++- .../kernel/file_systems/nfs4/OpenState.cpp | 27 +++++--- .../kernel/file_systems/nfs4/OpenState.h | 6 -- .../file_systems/nfs4/RPCCallbackServer.cpp | 1 + .../file_systems/nfs4/ReplyInterpreter.cpp | 49 ++++++++++++--- .../file_systems/nfs4/ReplyInterpreter.h | 4 +- .../file_systems/nfs4/RequestBuilder.cpp | 5 +- .../kernel/file_systems/nfs4/RequestBuilder.h | 3 +- 13 files changed, 182 insertions(+), 55 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Connection.cpp b/src/add-ons/kernel/file_systems/nfs4/Connection.cpp index 25ed74b9b4..cc4611b9d8 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Connection.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Connection.cpp @@ -551,7 +551,7 @@ ConnectionBase::Disconnect() status_t -ConnectionListener::Listen(ConnectionListener** _listener, uint16 port) +ConnectionListener::Listen(ConnectionListener** listener, uint16 port) { int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (sock < 0) @@ -577,16 +577,13 @@ ConnectionListener::Listen(ConnectionListener** _listener, uint16 port) address.fProtocol = IPPROTO_TCP; memset(&address.fAddress, 0, sizeof(address.fAddress)); - ConnectionListener* listener; - listener = new(std::nothrow) ConnectionListener(address); - if (listener == NULL) { + *listener = new(std::nothrow) ConnectionListener(address); + if (*listener == NULL) { close(sock); return B_NO_MEMORY; } - listener->fSocket = sock; - - *_listener = listener; + (*listener)->fSocket = sock; return B_OK; } diff --git a/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp b/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp index 95e95ae2f0..f4eb9906d4 100644 --- a/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp @@ -27,10 +27,16 @@ FileSystem::FileSystem() fPrev(NULL), fOpenFiles(NULL), fOpenCount(0), + fOpenOwnerSequence(0), fPath(NULL), fRoot(NULL), fId(1) { + fOpenOwner = rand(); + fOpenOwner <<= 32; + fOpenOwner |= rand(); + + mutex_init(&fOpenOwnerLock, NULL); mutex_init(&fOpenLock, NULL); } @@ -40,6 +46,7 @@ FileSystem::~FileSystem() NFSServer()->RemoveFileSystem(this); mutex_destroy(&fOpenLock); + mutex_destroy(&fOpenOwnerLock); free(const_cast(fPath)); delete fRoot; diff --git a/src/add-ons/kernel/file_systems/nfs4/FileSystem.h b/src/add-ons/kernel/file_systems/nfs4/FileSystem.h index 7b99ef720a..4c5df282e4 100644 --- a/src/add-ons/kernel/file_systems/nfs4/FileSystem.h +++ b/src/add-ons/kernel/file_systems/nfs4/FileSystem.h @@ -51,6 +51,10 @@ public: inline dev_t DevId() const; inline InodeIdMap* InoIdMap(); + inline uint64 OpenOwner() const; + inline uint32 OpenOwnerSequenceLock(); + inline void OpenOwnerSequenceUnlock(bool increment = true); + FileSystem* fNext; FileSystem* fPrev; private: @@ -62,6 +66,10 @@ private: uint32 fOpenCount; mutex fOpenLock; + uint64 fOpenOwner; + uint32 fOpenOwnerSequence; + mutex fOpenOwnerLock; + uint32 fExpireType; uint32 fSupAttrs[2]; @@ -163,5 +171,29 @@ FileSystem::InoIdMap() } +inline uint64 +FileSystem::OpenOwner() const +{ + return fOpenOwner; +} + + +inline uint32 +FileSystem::OpenOwnerSequenceLock() +{ + mutex_lock(&fOpenOwnerLock); + return fOpenOwnerSequence; +} + + +inline void +FileSystem::OpenOwnerSequenceUnlock(bool increment = true) +{ + if (increment) + fOpenOwnerSequence++; + mutex_unlock(&fOpenOwnerLock); +} + + #endif // FILESYSTEM_H diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h index c0abd7b0fd..1887ee2430 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h @@ -207,11 +207,32 @@ enum OpenClaim { CLAIM_DELEGATE_PREV = 3 }; +enum OpenDelegation { + OPEN_DELEGATE_NONE = 0, + OPEN_DELEGATE_READ = 1, + OPEN_DELEGATE_WRITE = 2 +}; + +struct OpenDelegationData { + OpenDelegation fType; + + uint32 fStateSeq; + uint32 fStateID[3]; + + bool fRecall; + uint64 fSpaceLimit; +}; + enum OpenFlags { OPEN4_RESULT_CONFIRM = 2, OPEN4_RESULT_LOCKTYPE_POSIX = 4 }; +enum { + NFS_LIMIT_SIZE = 1, + NFS_LIMIT_BLOCKS = 2 +}; + struct ChangeInfo { bool fAtomic; uint64 fBefore; diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp index cb8988178f..1c6722b3ef 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp @@ -389,6 +389,8 @@ NFS4Inode::CreateFile(const char* name, int mode, int perms, status_t result; bool badOwner = false; + OpenDelegationData delegation; + uint32 sequence = fFileSystem->OpenOwnerSequenceLock(); do { state->fClientID = fFileSystem->NFSServer()->ClientId(); @@ -396,8 +398,6 @@ NFS4Inode::CreateFile(const char* name, int mode, int perms, Request request(serv); RequestBuilder& req = request.Builder(); - state->fOwnerID = atomic_add64(&state->fLastOwnerID, 1); - req.PutFH(fInfo.fHandle); AttrValue cattr[4]; @@ -427,9 +427,9 @@ NFS4Inode::CreateFile(const char* name, int mode, int perms, i++; } - req.Open(CLAIM_NULL, state->fSequence++, sModeToAccess(mode), - state->fClientID, OPEN4_CREATE, state->fOwnerID, name, cattr, - i, (mode & O_EXCL) == O_EXCL); + req.Open(CLAIM_NULL, sequence, sModeToAccess(mode), + state->fClientID, OPEN4_CREATE, fFileSystem->OpenOwner(), name, + cattr, i, (mode & O_EXCL) == O_EXCL); req.GetFH(); @@ -439,22 +439,29 @@ NFS4Inode::CreateFile(const char* name, int mode, int perms, } result = request.Send(); - if (result != B_OK) + if (result != B_OK) { + fFileSystem->OpenOwnerSequenceUnlock(false); return result; + } ReplyInterpreter& reply = request.Reply(); if (reply.NFS4Error() == NFS4ERR_BADOWNER) { + fFileSystem->OpenOwnerSequenceUnlock(); + sequence = fFileSystem->OpenOwnerSequenceLock(); + badOwner = true; continue; } if (HandleErrors(reply.NFS4Error(), serv)) continue; + fFileSystem->OpenOwnerSequenceUnlock(); + reply.PutFH(); result = reply.Open(state->fStateID, &state->fStateSeq, &confirm, - &changeInfo->fBefore, &changeInfo->fAfter, &changeInfo->fAtomic); + &delegation, changeInfo); if (result != B_OK) return result; @@ -488,8 +495,10 @@ NFS4Inode::CreateFile(const char* name, int mode, int perms, status_t NFS4Inode::OpenFile(OpenState* state, int mode) { + OpenDelegationData delegation; bool confirm; status_t result; + uint32 sequence = fFileSystem->OpenOwnerSequenceLock(); do { state->fClientID = fFileSystem->NFSServer()->ClientId(); @@ -497,8 +506,6 @@ NFS4Inode::OpenFile(OpenState* state, int mode) Request request(serv); RequestBuilder& req = request.Builder(); - state->fOwnerID = atomic_add64(&state->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)) { @@ -526,22 +533,27 @@ NFS4Inode::OpenFile(OpenState* state, int mode) attr.fAttribute = FATTR4_SIZE; attr.fFreePointer = false; attr.fData.fValue64 = 0; - req.Open(CLAIM_NULL, state->fSequence++, sModeToAccess(mode), - state->fClientID, OPEN4_CREATE, state->fOwnerID, fInfo.fName, - &attr, 1, false); + req.Open(CLAIM_NULL, sequence, sModeToAccess(mode), + state->fClientID, OPEN4_CREATE, fFileSystem->OpenOwner(), + fInfo.fName, &attr, 1, false); } else - req.Open(CLAIM_NULL, state->fSequence++, sModeToAccess(mode), - state->fClientID, OPEN4_NOCREATE, state->fOwnerID, fInfo.fName); + req.Open(CLAIM_NULL, sequence, sModeToAccess(mode), state->fClientID, + OPEN4_NOCREATE, fFileSystem->OpenOwner(), fInfo.fName); + req.GetFH(); result = request.Send(); - if (result != B_OK) + if (result != B_OK) { + fFileSystem->OpenOwnerSequenceUnlock(false); return result; + } ReplyInterpreter& reply = request.Reply(); if (HandleErrors(reply.NFS4Error(), serv, NULL, state)) continue; + fFileSystem->OpenOwnerSequenceUnlock(); + // Verify if the file we want to open is the file this Inode // represents. if (fFileSystem->IsAttrSupported(FATTR4_FILEID) || @@ -558,7 +570,12 @@ NFS4Inode::OpenFile(OpenState* state, int mode) } reply.PutFH(); - result = reply.Open(state->fStateID, &state->fStateSeq, &confirm); + result = reply.Open(state->fStateID, &state->fStateSeq, &confirm, + &delegation); + + FileHandle handle; + reply.GetFH(&handle); + if (result != B_OK) return result; @@ -570,6 +587,9 @@ NFS4Inode::OpenFile(OpenState* state, int mode) if (confirm) return ConfirmOpen(fInfo.fHandle, state); + if (delegation.fType != OPEN_DELEGATE_NONE) + dprintf("GOT A DELEGATION!\n"); + return B_OK; } @@ -891,6 +911,7 @@ NFS4Inode::TestLock(OpenFileCookie* cookie, LockType* type, uint64* position, status_t NFS4Inode::AcquireLock(OpenFileCookie* cookie, LockInfo* lockInfo, bool wait) { + uint32 sequence = fFileSystem->OpenOwnerSequenceLock(); do { MutexLocker ownerLocker(lockInfo->fOwner->fLock); @@ -899,11 +920,13 @@ NFS4Inode::AcquireLock(OpenFileCookie* cookie, LockInfo* lockInfo, bool wait) RequestBuilder& req = request.Builder(); req.PutFH(fInfo.fHandle); - req.Lock(cookie, lockInfo); + req.Lock(cookie, lockInfo, sequence); status_t result = request.Send(); - if (result != B_OK) + if (result != B_OK) { + fFileSystem->OpenOwnerSequenceUnlock(false); return result; + } ReplyInterpreter &reply = request.Reply(); @@ -912,13 +935,16 @@ NFS4Inode::AcquireLock(OpenFileCookie* cookie, LockInfo* lockInfo, bool wait) ownerLocker.Unlock(); if (wait && reply.NFS4Error() == NFS4ERR_DENIED) { + fFileSystem->OpenOwnerSequenceUnlock(); snooze_etc(sSecToBigTime(5), B_SYSTEM_TIMEBASE, B_RELATIVE_TIMEOUT); + sequence = fFileSystem->OpenOwnerSequenceLock(); continue; } if (HandleErrors(reply.NFS4Error(), serv, cookie)) continue; + fFileSystem->OpenOwnerSequenceUnlock(); if (result != B_OK) return result; diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp index 73c5e3a5bb..073fd01c6c 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp @@ -103,6 +103,7 @@ NFS4Object::HandleErrors(uint32 nfs4Error, RPC::Server* serv, status_t NFS4Object::ConfirmOpen(const FileHandle& fh, OpenState* state) { + uint32 sequence = fFileSystem->OpenOwnerSequenceLock(); do { RPC::Server* serv = fFileSystem->Server(); Request request(serv); @@ -110,17 +111,21 @@ NFS4Object::ConfirmOpen(const FileHandle& fh, OpenState* state) RequestBuilder& req = request.Builder(); req.PutFH(fh); - req.OpenConfirm(state->fSequence++, state->fStateID, state->fStateSeq); + req.OpenConfirm(sequence, state->fStateID, state->fStateSeq); status_t result = request.Send(); - if (result != B_OK) + if (result != B_OK) { + fFileSystem->OpenOwnerSequenceUnlock(false); return result; + } ReplyInterpreter& reply = request.Reply(); if (HandleErrors(reply.NFS4Error(), serv)) continue; + fFileSystem->OpenOwnerSequenceUnlock(); + reply.PutFH(); result = reply.OpenConfirm(&state->fStateSeq); if (result != B_OK) diff --git a/src/add-ons/kernel/file_systems/nfs4/OpenState.cpp b/src/add-ons/kernel/file_systems/nfs4/OpenState.cpp index 4959199340..236ff7c243 100644 --- a/src/add-ons/kernel/file_systems/nfs4/OpenState.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/OpenState.cpp @@ -15,11 +15,8 @@ #include "Request.h" -vint64 OpenState::fLastOwnerID = 0; - OpenState::OpenState() : - fSequence(0), fOpened(false) { mutex_init(&fLock, NULL); @@ -46,27 +43,34 @@ OpenState::Reclaim(uint64 newClientID) fClientID = newClientID; bool confirm; + OpenDelegationData delegation; + + uint32 sequence = fFileSystem->OpenOwnerSequenceLock(); do { RPC::Server* server = fFileSystem->Server(); Request request(server); RequestBuilder& req = request.Builder(); req.PutFH(fInfo.fHandle); - req.Open(CLAIM_PREVIOUS, fSequence++, sModeToAccess(fMode), newClientID, - OPEN4_NOCREATE, fOwnerID, NULL); + req.Open(CLAIM_PREVIOUS, sequence, sModeToAccess(fMode), newClientID, + OPEN4_NOCREATE, fFileSystem->OpenOwner(), NULL); status_t result = request.Send(); - if (result != B_OK) + if (result != B_OK) { + fFileSystem->OpenOwnerSequenceUnlock(false); return result; + } ReplyInterpreter& reply = request.Reply(); if (HandleErrors(reply.NFS4Error(), server)) continue; + fFileSystem->OpenOwnerSequenceUnlock(); + reply.PutFH(); - result = reply.Open(fStateID, &fStateSeq, &confirm); + result = reply.Open(fStateID, &fStateSeq, &confirm, &delegation); if (result != B_OK) return result; } while (true); @@ -87,24 +91,29 @@ OpenState::Close() MutexLocker _(fLock); fOpened = false; + uint32 sequence = fFileSystem->OpenOwnerSequenceLock(); do { RPC::Server* serv = fFileSystem->Server(); Request request(serv); RequestBuilder& req = request.Builder(); req.PutFH(fInfo.fHandle); - req.Close(fSequence++, fStateID, fStateSeq); + req.Close(sequence, fStateID, fStateSeq); status_t result = request.Send(); - if (result != B_OK) + if (result != B_OK) { + fFileSystem->OpenOwnerSequenceUnlock(false); return result; + } ReplyInterpreter& reply = request.Reply(); if (HandleErrors(reply.NFS4Error(), serv, NULL, this)) continue; + fFileSystem->OpenOwnerSequenceUnlock(); reply.PutFH(); + return reply.Close(); } while (true); } diff --git a/src/add-ons/kernel/file_systems/nfs4/OpenState.h b/src/add-ons/kernel/file_systems/nfs4/OpenState.h index 00da687bd2..ecf10a8a41 100644 --- a/src/add-ons/kernel/file_systems/nfs4/OpenState.h +++ b/src/add-ons/kernel/file_systems/nfs4/OpenState.h @@ -28,14 +28,8 @@ struct OpenState : public NFS4Object, public KernelReferenceable { uint32 fStateID[3]; uint32 fStateSeq; - uint32 fSequence; - - uint64 fOwnerID; - static vint64 fLastOwnerID; - bool fOpened; - status_t Reclaim(uint64 newClientID); status_t Close(); diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCCallbackServer.cpp b/src/add-ons/kernel/file_systems/nfs4/RPCCallbackServer.cpp index 651ccc5426..5a64700092 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RPCCallbackServer.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RPCCallbackServer.cpp @@ -287,6 +287,7 @@ CallbackServer::ListenerThread() { while (fThreadRunning) { Connection* connection; + status_t result = fListener->AcceptConnection(&connection); if (result != B_OK) { fThreadRunning = false; diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp index 56ba582894..2b74de3b17 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp @@ -266,8 +266,8 @@ ReplyInterpreter::LockU(LockInfo* linfo) status_t -ReplyInterpreter::Open(uint32* id, uint32* seq, bool* confirm, uint64* _before, - uint64* _after, bool* _atomic) +ReplyInterpreter::Open(uint32* id, uint32* seq, bool* confirm, + OpenDelegationData* delegData, ChangeInfo* changeInfo) { status_t res = _OperationError(OpOpen); if (res != B_OK) @@ -280,14 +280,13 @@ ReplyInterpreter::Open(uint32* id, uint32* seq, bool* confirm, uint64* _before, // change info bool atomic = fReply->Stream().GetBoolean(); - if (_atomic != NULL) - *_atomic = atomic; uint64 before = fReply->Stream().GetUHyper(); - if (_before != NULL) - *_before = before; uint64 after = fReply->Stream().GetUHyper(); - if (_after != NULL) - *_after = after; + if (changeInfo != NULL) { + changeInfo->fAtomic = atomic; + changeInfo->fBefore = before; + changeInfo->fAfter = after; + } uint32 flags = fReply->Stream().GetUInt(); *confirm = (flags & OPEN4_RESULT_CONFIRM) == OPEN4_RESULT_CONFIRM; @@ -298,7 +297,41 @@ ReplyInterpreter::Open(uint32* id, uint32* seq, bool* confirm, uint64* _before, fReply->Stream().GetUInt(); // delegation info + uint32 delegation = fReply->Stream().GetUInt(); + if (delegation == OPEN_DELEGATE_NONE) { + delegData->fType = OPEN_DELEGATE_NONE; + return fReply->Stream().IsEOF() ? B_BAD_VALUE : B_OK; + } + + delegData->fStateSeq = fReply->Stream().GetUInt(); + delegData->fStateID[0] = fReply->Stream().GetUInt(); + delegData->fStateID[1] = fReply->Stream().GetUInt(); + delegData->fStateID[2] = fReply->Stream().GetUInt(); + + delegData->fRecall = fReply->Stream().GetBoolean(); + + switch (delegation) { + case OPEN_DELEGATE_READ: + delegData->fType = OPEN_DELEGATE_READ; + break; + case OPEN_DELEGATE_WRITE: + delegData->fType = OPEN_DELEGATE_WRITE; + + int32 limitBy = fReply->Stream().GetInt(); + if (limitBy == NFS_LIMIT_SIZE) + delegData->fSpaceLimit = fReply->Stream().GetUHyper(); + else if (limitBy == NFS_LIMIT_BLOCKS) { + uint32 numBlocks = fReply->Stream().GetUInt(); + delegData->fSpaceLimit = fReply->Stream().GetUInt() * numBlocks; + } + break; + } + + // ACE data fReply->Stream().GetUInt(); + fReply->Stream().GetUInt(); + fReply->Stream().GetUInt(); + fReply->Stream().GetOpaque(NULL); return fReply->Stream().IsEOF() ? B_BAD_VALUE : B_OK; } diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h index ed3a2695a1..892e34cc41 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h @@ -81,8 +81,8 @@ public: inline status_t LookUpUp(); inline status_t Nverify(); status_t Open(uint32* id, uint32* seq, bool* confirm, - uint64* before = NULL, uint64* after = NULL, - bool* atomic = NULL); + OpenDelegationData* delegData, + ChangeInfo* changeInfo = NULL); status_t OpenConfirm(uint32* stateSeq); inline status_t PutFH(); inline status_t PutRootFH(); diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp index c9d2408503..c6a0e80cda 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp @@ -186,7 +186,8 @@ RequestBuilder::_GenerateLockOwner(XDR::WriteStream& stream, status_t -RequestBuilder::Lock(OpenFileCookie* cookie, LockInfo* lock, bool reclaim) +RequestBuilder::Lock(OpenFileCookie* cookie, LockInfo* lock, uint32 sequence, + bool reclaim) { if (fProcedure != ProcCompound) return B_BAD_VALUE; @@ -213,7 +214,7 @@ RequestBuilder::Lock(OpenFileCookie* cookie, LockInfo* lock, bool reclaim) else state = cookie->fWriteState; - fRequest->Stream().AddUInt(state->fSequence++); + fRequest->Stream().AddUInt(sequence); fRequest->Stream().AddUInt(state->fStateSeq); fRequest->Stream().AddUInt(state->fStateID[0]); fRequest->Stream().AddUInt(state->fStateID[1]); diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h index a8f2d7618d..13db57de2b 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h @@ -41,7 +41,8 @@ public: status_t GetFH(); status_t Link(const char* name); status_t Lock(OpenFileCookie* cookie, - LockInfo* lock, bool reclaim = false); + LockInfo* lock, uint32 sequence, + bool reclaim = false); status_t LockT(LockType type, uint64 pos, uint64 len, OpenFileCookie* cookie); status_t LockU(LockInfo* lock); From 52aaad172fd93ba9b286d237dd299746e6458e1b Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Sun, 5 Aug 2012 22:07:44 +0200 Subject: [PATCH 161/252] nfs4: Use one open state per inode --- .../kernel/file_systems/nfs4/Cookie.cpp | 1 - src/add-ons/kernel/file_systems/nfs4/Cookie.h | 5 +- .../kernel/file_systems/nfs4/Delegation.h | 43 +++++++ .../kernel/file_systems/nfs4/Inode.cpp | 5 +- src/add-ons/kernel/file_systems/nfs4/Inode.h | 19 ++- .../kernel/file_systems/nfs4/InodeIdMap.h | 1 + .../kernel/file_systems/nfs4/InodeRegular.cpp | 117 +++++------------- .../kernel/file_systems/nfs4/NFS4Inode.cpp | 8 +- .../kernel/file_systems/nfs4/NFS4Inode.h | 5 +- .../kernel/file_systems/nfs4/NFS4Object.cpp | 15 +-- .../kernel/file_systems/nfs4/NFS4Server.cpp | 12 +- .../file_systems/nfs4/ReplyInterpreter.cpp | 4 + .../file_systems/nfs4/RequestBuilder.cpp | 15 +-- .../file_systems/nfs4/kernel_interface.cpp | 22 +++- 14 files changed, 137 insertions(+), 135 deletions(-) create mode 100644 src/add-ons/kernel/file_systems/nfs4/Delegation.h diff --git a/src/add-ons/kernel/file_systems/nfs4/Cookie.cpp b/src/add-ons/kernel/file_systems/nfs4/Cookie.cpp index 83d0336a8b..a2970b7a95 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Cookie.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Cookie.cpp @@ -161,7 +161,6 @@ OpenFileCookie::GetLockOwner(uint32 owner) if (current == NULL) return NULL; - current->fClientId = fClientID; current->fNext = fLockOwners; if (fLockOwners != NULL) fLockOwners->fPrev = current; diff --git a/src/add-ons/kernel/file_systems/nfs4/Cookie.h b/src/add-ons/kernel/file_systems/nfs4/Cookie.h index baeca6706d..4af8899333 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Cookie.h +++ b/src/add-ons/kernel/file_systems/nfs4/Cookie.h @@ -71,10 +71,7 @@ struct Cookie { }; struct OpenFileCookie : public Cookie { - uint64 fClientID; - - OpenState* fReadState; - OpenState* fWriteState; + OpenState* fOpenState; uint32 fMode; diff --git a/src/add-ons/kernel/file_systems/nfs4/Delegation.h b/src/add-ons/kernel/file_systems/nfs4/Delegation.h new file mode 100644 index 0000000000..31fea04344 --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/Delegation.h @@ -0,0 +1,43 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ +#ifndef DELEGATION_H +#define DELEGATION_H + + +#include +#include + +#include "NFS4Object.h" + + +class Delegation : public NFS4Object { +public: + Delegation(OpenDelegationData data, Inode* inode, + uint64 clientID); + ~Delegation(); + + status_t Write(void* buffer, uint32* size); + status_t Read(void* buffer, uint32* size); + + // TODO: locks + + status_t Reclaim(uint64 newClientID); + + status_t GiveUp(bool flush); + +private: + uint64 fClientID; + OpenDelegationData fData; + Inode* fInode; + + rw_lock fLock; +}; + + +#endif // DELEGATION_H + diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index 007890e310..edfbddffde 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -24,8 +24,7 @@ Inode::Inode() : fCache(NULL), fFileCache(NULL), - fWriteState(NULL), - fReadState(NULL), + fOpenState(NULL), fWriteDirty(false) { mutex_init(&fStateLock, NULL); @@ -530,7 +529,7 @@ Inode::WriteStat(const struct stat* st, uint32 mask) } MutexLocker stateLocker(fStateLock); - result = NFS4Inode::WriteStat(fWriteState, attr, i); + result = NFS4Inode::WriteStat(fOpenState, attr, i); stateLocker.Unlock(); fMetaCache.InvalidateStat(); diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h b/src/add-ons/kernel/file_systems/nfs4/Inode.h index e4bfa9ac6b..58250e7521 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -14,6 +14,8 @@ #include "OpenState.h" +class Delegation; + class Inode : public NFS4Inode { public: static status_t CreateInode(FileSystem* fs, const FileInfo& fi, @@ -25,6 +27,8 @@ public: inline const char* Name() const; inline FileSystem* GetFileSystem() const; + inline void SetOpenState(OpenState* state); + inline void* FileCache(); status_t RevalidateFileCache(); @@ -93,17 +97,20 @@ protected: static inline ino_t FileIdToInoT(uint64 fileid); +private: uint32 fType; MetadataCache fMetaCache; DirectoryCache* fCache; + rw_lock fDelegationLock; + Delegation* fDelegation; + uint64 fChange; void* fFileCache; mutex fFileCacheLock; - OpenState* fWriteState; - OpenState* fReadState; + OpenState* fOpenState; mutex fStateLock; bool fWriteDirty; @@ -156,5 +163,13 @@ Inode::FileCache() } +inline void +Inode::SetOpenState(OpenState* state) +{ + MutexLocker _(fStateLock); + fOpenState = state; +} + + #endif // INODE_H diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeIdMap.h b/src/add-ons/kernel/file_systems/nfs4/InodeIdMap.h index 63ec1b07b3..2a29e07942 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeIdMap.h +++ b/src/add-ons/kernel/file_systems/nfs4/InodeIdMap.h @@ -52,6 +52,7 @@ inline status_t InodeIdMap::AddEntry(const FileInfo& fi, ino_t id) { MutexLocker _(fLock); + fMap.Remove(id); return fMap.Insert(id, fi); } diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp index 51d41229c9..c82c507da5 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp @@ -70,44 +70,19 @@ Inode::Create(const char* name, int mode, int perms, OpenFileCookie* cookie, cookie->fLocks = NULL; MutexLocker _(fStateLock); - int openMode = mode & O_RWMASK; - if (openMode == O_WRONLY || openMode == O_RDWR) { - OpenState* state = new OpenState; - status_t result = CreateState(name, O_WRONLY, perms, state); - if (result != B_OK) - return result; + OpenState* state = new OpenState; + status_t result = CreateState(name, mode, perms, state); + if (result != B_OK) + return result; - fWriteState = state; - *id = FileIdToInoT(cookie->fWriteState->fInfo.fFileId); - cookie->fWriteState = fWriteState; - } + cookie->fOpenState = state; + fOpenState = state; - if (openMode == O_RDONLY || openMode == O_RDWR) { - OpenState* state = new OpenState; - state->fInfo = fInfo; - state->fFileSystem = fFileSystem; - - status_t result; - if (openMode == O_RDWR) - result = OpenFile(state, O_RDONLY); - else - result = CreateState(name, O_RDONLY, perms, state); - - if (result != B_OK) { - if (fWriteState != NULL) - if (fWriteState->ReleaseReference() == 1) - fWriteState = NULL; - return result; - } - - fReadState = state; - *id = FileIdToInoT(cookie->fReadState->fInfo.fFileId); - cookie->fReadState = fReadState; - } + *id = FileIdToInoT(state->fInfo.fFileId); + cookie->fOpenState = fOpenState; cookie->fFileSystem = fFileSystem; - cookie->fClientID = fFileSystem->NFSServer()->ClientId(); fFileSystem->AddOpenFile(cookie); fFileSystem->Root()->MakeInfoInvalid(); @@ -120,55 +95,33 @@ status_t Inode::Open(int mode, OpenFileCookie* cookie) { MutexLocker _(fStateLock); - int openMode = mode & O_RWMASK; - if (openMode == O_WRONLY || openMode == O_RDWR) { - if (fWriteState == NULL) { - OpenState* state = new OpenState; - if (state == NULL) - return B_NO_MEMORY; + if (fOpenState == NULL) { + OpenState* state = new OpenState; + if (state == NULL) + return B_NO_MEMORY; - state->fInfo = fInfo; - state->fFileSystem = fFileSystem; - status_t result = OpenFile(state, O_WRONLY); + state->fInfo = fInfo; + state->fFileSystem = fFileSystem; + status_t result = OpenFile(state, mode, NULL); + if (result != B_OK) + return result; + + fOpenState = state; + } else { + int newMode = mode & O_RWMASK; + int oldMode = fOpenState->fMode & O_RWMASK; + if (oldMode != newMode && oldMode != O_RDWR) { + status_t result = OpenFile(fOpenState, O_RDWR, NULL); if (result != B_OK) return result; - - fWriteState = state; - } else - fWriteState->AcquireReference(); - - cookie->fWriteState = fWriteState; + fOpenState->fMode = O_RDWR; + } + fOpenState->AcquireReference(); } - if (openMode == O_RDONLY || openMode == O_RDWR) { - if (fReadState == NULL) { - OpenState* state = new OpenState; - if (state == NULL) { - if (fWriteState != NULL) - if (fWriteState->ReleaseReference() == 1) - fWriteState = NULL; - return B_NO_MEMORY; - } + cookie->fOpenState = fOpenState; - state->fInfo = fInfo; - state->fFileSystem = fFileSystem; - status_t result = OpenFile(state, O_RDONLY); - if (result != B_OK) { - if (fWriteState != NULL) - if (fWriteState->ReleaseReference() == 1) - fWriteState = NULL; - return result; - } - - fReadState = state; - } else - fReadState->AcquireReference(); - - cookie->fReadState = fReadState; - } - - cookie->fClientID = fFileSystem->NFSServer()->ClientId(); cookie->fFileSystem = fFileSystem; cookie->fMode = mode; cookie->fLocks = NULL; @@ -185,13 +138,9 @@ Inode::Close(OpenFileCookie* cookie) fFileSystem->RemoveOpenFile(cookie); MutexLocker _(fStateLock); - if (cookie->fWriteState != NULL) - if (cookie->fWriteState->ReleaseReference() == 1) - fWriteState = NULL; - - if (cookie->fReadState != NULL) - if (cookie->fReadState->ReleaseReference() == 1) - fReadState = NULL; + if (cookie->fOpenState != NULL) + if (cookie->fOpenState->ReleaseReference() == 1) + fOpenState = NULL; return B_OK; } @@ -207,7 +156,7 @@ Inode::Read(OpenFileCookie* cookie, off_t pos, void* buffer, size_t* _length, status_t result; while (size < *_length && !*eof) { uint32 len = *_length - size; - result = ReadFile(cookie, fReadState, pos + size, &len, + result = ReadFile(cookie, fOpenState, pos + size, &len, reinterpret_cast(buffer) + size, eof); if (result != B_OK) { if (size == 0) @@ -236,7 +185,7 @@ Inode::Write(OpenFileCookie* cookie, off_t pos, const void* _buffer, while (size < *_length) { uint32 len = *_length - size; - status_t result = WriteFile(cookie, fWriteState, pos + size, &len, + status_t result = WriteFile(cookie, fOpenState, pos + size, &len, buffer + size); if (result != B_OK) { if (size == 0) diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp index 1c6722b3ef..c2208fb8af 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp @@ -493,9 +493,8 @@ NFS4Inode::CreateFile(const char* name, int mode, int perms, status_t -NFS4Inode::OpenFile(OpenState* state, int mode) +NFS4Inode::OpenFile(OpenState* state, int mode, OpenDelegationData* delegation) { - OpenDelegationData delegation; bool confirm; status_t result; uint32 sequence = fFileSystem->OpenOwnerSequenceLock(); @@ -571,7 +570,7 @@ NFS4Inode::OpenFile(OpenState* state, int mode) reply.PutFH(); result = reply.Open(state->fStateID, &state->fStateSeq, &confirm, - &delegation); + delegation); FileHandle handle; reply.GetFH(&handle); @@ -587,9 +586,6 @@ NFS4Inode::OpenFile(OpenState* state, int mode) if (confirm) return ConfirmOpen(fInfo.fHandle, state); - if (delegation.fType != OPEN_DELEGATE_NONE) - dprintf("GOT A DELEGATION!\n"); - return B_OK; } diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h index 027f6a4917..dbcf90a1c8 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h @@ -33,7 +33,7 @@ protected: status_t LookUp(const char* name, uint64* change, uint64* fileID, FileHandle* handle); - status_t Link(Inode* dir, const char* name, + status_t Link(Inode* dir, const char* name,s ChangeInfo* changeInfo); static status_t Rename(Inode* from, Inode* to, const char* fromName, @@ -47,7 +47,8 @@ protected: status_t CreateFile(const char* name, int mode, int perms, OpenState* state, ChangeInfo* changeInfo, uint64* fileID, FileHandle* handle); - status_t OpenFile(OpenState* state, int mode); + status_t OpenFile(OpenState* state, int mode, + OpenDelegationData* delegation); status_t ReadFile(OpenFileCookie* cookie, OpenState* state, uint64 position, uint32* length, void* buffer, diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp index 073fd01c6c..327c075246 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp @@ -19,6 +19,9 @@ NFS4Object::HandleErrors(uint32 nfs4Error, RPC::Server* serv, { uint32 leaseTime; + if (cookie != NULL) + state = cookie->fOpenState; + switch (nfs4Error) { case NFS4_OK: return false; @@ -62,10 +65,7 @@ NFS4Object::HandleErrors(uint32 nfs4Error, RPC::Server* serv, // server has rebooted, reclaim share and try again case NFS4ERR_STALE_CLIENTID: case NFS4ERR_STALE_STATEID: - if (cookie != NULL) { - fFileSystem->NFSServer()->ServerRebooted(cookie->fClientID); - return true; - } else if (state != NULL) { + if (state != NULL) { fFileSystem->NFSServer()->ServerRebooted(state->fClientID); return true; } @@ -85,10 +85,7 @@ NFS4Object::HandleErrors(uint32 nfs4Error, RPC::Server* serv, // lease has expired case NFS4ERR_EXPIRED: - if (cookie != NULL) { - fFileSystem->NFSServer()->ClientId(cookie->fClientID, true); - return true; - } else if (state != NULL) { + if (state != NULL) { fFileSystem->NFSServer()->ClientId(state->fClientID, true); return true; } @@ -121,7 +118,7 @@ NFS4Object::ConfirmOpen(const FileHandle& fh, OpenState* state) ReplyInterpreter& reply = request.Reply(); - if (HandleErrors(reply.NFS4Error(), serv)) + if (HandleErrors(reply.NFS4Error(), serv, NULL, state)) continue; fFileSystem->OpenOwnerSequenceUnlock(); diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp index 412a653866..ec38c3af13 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp @@ -59,7 +59,6 @@ NFS4Server::ServerRebooted(uint64 clientId) while (fs != NULL) { OpenFileCookie* current = fs->OpenFilesLock(); while (current != NULL) { - current->fClientID = fClientId; _ReclaimOpen(current); _ReclaimLocks(current); current = current->fNext; @@ -75,10 +74,8 @@ NFS4Server::ServerRebooted(uint64 clientId) status_t NFS4Server::_ReclaimOpen(OpenFileCookie* cookie) { - if (cookie->fWriteState != NULL) - cookie->fWriteState->Reclaim(fClientId); - if (cookie->fReadState != NULL) - cookie->fReadState->Reclaim(fClientId); + if (cookie->fOpenState != NULL) + cookie->fOpenState->Reclaim(fClientId); return B_OK; } @@ -100,10 +97,7 @@ NFS4Server::_ReclaimLocks(OpenFileCookie* cookie) Request request(fServer); RequestBuilder& req = request.Builder(); - if (cookie->fWriteState != NULL) - req.PutFH(cookie->fWriteState->fInfo.fHandle); - else - req.PutFH(cookie->fReadState->fInfo.fHandle); + req.PutFH(cookie->fOpenState->fInfo.fHandle); req.Lock(cookie, linfo, true); status_t result = request.Send(); diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp index 2b74de3b17..b26082d78f 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp @@ -298,6 +298,10 @@ ReplyInterpreter::Open(uint32* id, uint32* seq, bool* confirm, // delegation info uint32 delegation = fReply->Stream().GetUInt(); + OpenDelegationData data; + if (delegData == NULL) + delegData = &data; + if (delegation == OPEN_DELEGATE_NONE) { delegData->fType = OPEN_DELEGATE_NONE; return fReply->Stream().IsEOF() ? B_BAD_VALUE : B_OK; diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp index c6a0e80cda..c05b873a11 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp @@ -173,14 +173,11 @@ void RequestBuilder::_GenerateLockOwner(XDR::WriteStream& stream, OpenFileCookie* cookie, LockOwner* owner) { - stream.AddUHyper(cookie->fClientID); + stream.AddUHyper(cookie->fOpenState->fClientID); uint64 lockOwner[2]; lockOwner[0] = owner->fOwner; - if (cookie->fWriteState != NULL) - lockOwner[1] = cookie->fWriteState->fInfo.fFileId; - else - lockOwner[1] = cookie->fReadState->fInfo.fFileId; + lockOwner[1] = cookie->fOpenState->fInfo.fFileId; stream.AddOpaque(lockOwner, sizeof(lockOwner)); } @@ -208,11 +205,7 @@ RequestBuilder::Lock(OpenFileCookie* cookie, LockInfo* lock, uint32 sequence, fRequest->Stream().AddBoolean(true); // new lock owner // open seq stateid - OpenState* state; - if (lock->fType == READ_LT || lock->fType == READW_LT) - state = cookie->fReadState; - else - state = cookie->fWriteState; + OpenState* state = cookie->fOpenState; fRequest->Stream().AddUInt(sequence); fRequest->Stream().AddUInt(state->fStateSeq); @@ -258,7 +251,7 @@ RequestBuilder::LockT(LockType type, uint64 pos, uint64 len, fRequest->Stream().AddUHyper(pos); fRequest->Stream().AddUHyper(len); - fRequest->Stream().AddUHyper(cookie->fClientID); + fRequest->Stream().AddUHyper(cookie->fOpenState->fClientID); uint32 owner = find_thread(NULL); fRequest->Stream().AddOpaque(&owner, sizeof(owner)); 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 95b8bd87eb..d1a447bc09 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -400,10 +400,24 @@ nfs4_create(fs_volume* volume, fs_vnode* dir, const char* name, int openMode, return result; } - void* ptr; - result = get_vnode(volume, *_newVnodeID, &ptr); - if (result != B_OK) - delete cookie; + Inode* child; + result = get_vnode(volume, *_newVnodeID, reinterpret_cast(&child)); + if (result != B_OK) { + result = inode->GetFileSystem()->GetInode(*_newVnodeID, &child); + if (result != B_OK) { + delete cookie; + return result; + } + + result = new_vnode(volume, *_newVnodeID, child, &gNFSv4VnodeOps); + if (result != B_OK) { + delete child; + delete cookie; + return result; + } + } + + child->SetOpenState(cookie->fOpenState); return result; } From e743e243206509ccb41281a1aab140597bfb40b7 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Sun, 5 Aug 2012 22:49:44 +0200 Subject: [PATCH 162/252] nfs4: Move cache management inside Inode class --- .../kernel/file_systems/nfs4/Inode.cpp | 7 +++ src/add-ons/kernel/file_systems/nfs4/Inode.h | 17 ++++++- .../kernel/file_systems/nfs4/InodeRegular.cpp | 51 ++++++++++++++++++- .../kernel/file_systems/nfs4/NFS4Inode.h | 2 +- .../file_systems/nfs4/kernel_interface.cpp | 35 +++++-------- 5 files changed, 85 insertions(+), 27 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index edfbddffde..a573f4989d 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -24,6 +24,7 @@ Inode::Inode() : fCache(NULL), fFileCache(NULL), + fMaxFileSize(0), fOpenState(NULL), fWriteDirty(false) { @@ -638,6 +639,9 @@ Inode::AcquireLock(OpenFileCookie* cookie, const struct flock* lock, status_t Inode::ReleaseLock(OpenFileCookie* cookie, const struct flock* lock) { + file_cache_sync(fFileCache); + Commit(); + LockInfo* prev = NULL; thread_info info; @@ -673,6 +677,9 @@ Inode::ReleaseLock(OpenFileCookie* cookie, const struct flock* lock) status_t Inode::ReleaseAllLocks(OpenFileCookie* cookie) { + file_cache_sync(fFileCache); + Commit(); + MutexLocker _(cookie->fLocksLock); LockInfo* linfo = cookie->fLocks; while (linfo != NULL) { diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h b/src/add-ons/kernel/file_systems/nfs4/Inode.h index 58250e7521..a44c12b584 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -32,6 +32,8 @@ public: inline void* FileCache(); status_t RevalidateFileCache(); + inline uint64 MaxFileSize(); + status_t LookUp(const char* name, ino_t* id); status_t Access(int mode); @@ -57,10 +59,15 @@ public: status_t Open(int mode, OpenFileCookie* cookie); status_t Close(OpenFileCookie* cookie); status_t Read(OpenFileCookie* cookie, off_t pos, - void* buffer, size_t* length, bool* eof); + void* buffer, size_t* length); status_t Write(OpenFileCookie* cookie, off_t pos, const void* buffer, size_t *_length); + status_t ReadDirect(OpenFileCookie* cookie, off_t pos, + void* buffer, size_t* length, bool* eof); + status_t WriteDirect(OpenFileCookie* cookie, off_t pos, + const void* buffer, size_t *_length); + status_t CreateDir(const char* name, int mode); status_t OpenDir(OpenDirCookie* cookie); status_t ReadDir(void* buffer, uint32 size, @@ -109,6 +116,7 @@ private: uint64 fChange; void* fFileCache; mutex fFileCacheLock; + uint64 fMaxFileSize; OpenState* fOpenState; mutex fStateLock; @@ -171,5 +179,12 @@ Inode::SetOpenState(OpenState* state) } +inline uint64 +Inode::MaxFileSize() +{ + return fMaxFileSize; +} + + #endif // INODE_H diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp index c82c507da5..34ca35e1f8 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp @@ -135,6 +135,9 @@ Inode::Open(int mode, OpenFileCookie* cookie) status_t Inode::Close(OpenFileCookie* cookie) { + file_cache_sync(fFileCache); + Commit(); + fFileSystem->RemoveOpenFile(cookie); MutexLocker _(fStateLock); @@ -147,12 +150,15 @@ Inode::Close(OpenFileCookie* cookie) status_t -Inode::Read(OpenFileCookie* cookie, off_t pos, void* buffer, size_t* _length, +Inode::ReadDirect(OpenFileCookie* cookie, off_t pos, void* buffer, size_t* _length, bool* eof) { *eof = false; uint32 size = 0; + uint32 ioSize = fFileSystem->Root()->IOSize(); + *_length = min_c(ioSize, *_length); + status_t result; while (size < *_length && !*eof) { uint32 len = *_length - size; @@ -175,12 +181,25 @@ Inode::Read(OpenFileCookie* cookie, off_t pos, void* buffer, size_t* _length, status_t -Inode::Write(OpenFileCookie* cookie, off_t pos, const void* _buffer, +Inode::Read(OpenFileCookie* cookie, off_t pos, void* buffer, size_t* _length) +{ + bool eof = false; + if ((cookie->fMode & O_NOCACHE) != 0) + return ReadDirect(cookie, pos, buffer, _length, &eof); + return file_cache_read(fFileCache, cookie, pos, buffer, _length); +} + + +status_t +Inode::WriteDirect(OpenFileCookie* cookie, off_t pos, const void* _buffer, size_t *_length) { uint32 size = 0; const char* buffer = reinterpret_cast(_buffer); + uint32 ioSize = fFileSystem->Root()->IOSize(); + *_length = min_c(ioSize, *_length); + fWriteDirty = true; while (size < *_length) { @@ -206,6 +225,34 @@ Inode::Write(OpenFileCookie* cookie, off_t pos, const void* _buffer, } +status_t +Inode::Write(OpenFileCookie* cookie, off_t pos, const void* _buffer, + size_t *_length) +{ + struct stat st; + status_t result = Stat(&st); + if (result != B_OK) + return result; + + if ((cookie->fMode & O_APPEND) != 0) + pos = st.st_size; + + uint64 fileSize = max_c(st.st_size, pos + *_length); + fMaxFileSize = max_c(fMaxFileSize, fileSize); + + if ((cookie->fMode & O_NOCACHE) != 0) { + WriteDirect(cookie, pos, _buffer, _length); + Commit(); + } + + result = file_cache_set_size(fFileCache, fileSize); + if (result != B_OK) + return result; + + return file_cache_write(fFileCache, cookie, pos, _buffer, _length); +} + + status_t Inode::Commit() { diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h index dbcf90a1c8..968e6705b5 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h @@ -33,7 +33,7 @@ protected: status_t LookUp(const char* name, uint64* change, uint64* fileID, FileHandle* handle); - status_t Link(Inode* dir, const char* name,s + status_t Link(Inode* dir, const char* name, ChangeInfo* changeInfo); static status_t Rename(Inode* from, Inode* to, const char* fromName, 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 d1a447bc09..4804c6cce7 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -230,7 +230,7 @@ nfs4_read_pages(fs_volume* _volume, fs_vnode* vnode, void* _cookie, off_t pos, do { size_t bytesRead = bytesLeft; - result = inode->Read(cookie, pos, buffer, &bytesRead, &eof); + result = inode->ReadDirect(cookie, pos, buffer, &bytesRead, &eof); if (result != B_OK) return result; @@ -255,15 +255,17 @@ nfs4_write_pages(fs_volume* _volume, fs_vnode* vnode, void* _cookie, off_t pos, OpenFileCookie* cookie = reinterpret_cast(_cookie); status_t result; - uint32 ioSize = inode->GetFileSystem()->Root()->IOSize(); for (size_t i = 0; i < count; i++) { - size_t bytesLeft = vecs[i].iov_len; + uint64 bytesLeft = vecs[i].iov_len; + if (pos + bytesLeft > inode->MaxFileSize()) + bytesLeft = inode->MaxFileSize() - pos; + char* buffer = reinterpret_cast(vecs[i].iov_base); do { - size_t bytesWritten = min_c(ioSize, bytesLeft); + size_t bytesWritten = bytesLeft; - result = inode->Write(cookie, pos, buffer, &bytesWritten); + result = inode->WriteDirect(cookie, pos, buffer, &bytesWritten); if (result != B_OK) return result; @@ -468,8 +470,6 @@ nfs4_free_cookie(fs_volume* volume, fs_vnode* vnode, void* _cookie) return B_OK; OpenFileCookie* cookie = reinterpret_cast(_cookie); - file_cache_sync(inode->FileCache()); - inode->Commit(); inode->Close(cookie); delete cookie; @@ -479,7 +479,7 @@ nfs4_free_cookie(fs_volume* volume, fs_vnode* vnode, void* _cookie) static status_t -nfs4_read(fs_volume* volume, fs_vnode* vnode, void* cookie, off_t pos, +nfs4_read(fs_volume* volume, fs_vnode* vnode, void* _cookie, off_t pos, void* buffer, size_t* length) { Inode* inode = reinterpret_cast(vnode->private_node); @@ -490,7 +490,9 @@ nfs4_read(fs_volume* volume, fs_vnode* vnode, void* cookie, off_t pos, if (inode->Type() == S_IFLNK) return B_BAD_VALUE; - return file_cache_read(inode->FileCache(), cookie, pos, buffer, length); + OpenFileCookie* cookie = reinterpret_cast(_cookie); + + return inode->Read(cookie, pos, buffer, length); } @@ -508,17 +510,7 @@ nfs4_write(fs_volume* volume, fs_vnode* vnode, void* _cookie, off_t pos, OpenFileCookie* cookie = reinterpret_cast(_cookie); - struct stat stat; - status_t result = inode->Stat(&stat); - if (result != B_OK) - return result; - - uint64 fileSize = max_c(stat.st_size, pos + *length); - result = file_cache_set_size(inode->FileCache(), fileSize); - if (result != B_OK) - return result; - - return file_cache_write(inode->FileCache(), cookie, pos, _buffer, length); + return inode->Write(cookie, pos, _buffer, length); } @@ -627,9 +619,6 @@ nfs4_release_lock(fs_volume* volume, fs_vnode* vnode, void* _cookie, OpenFileCookie* cookie = reinterpret_cast(_cookie); - file_cache_sync(inode->FileCache()); - inode->Commit(); - if (lock != NULL) return inode->ReleaseLock(cookie, lock); else From 4a153753100503cf374d01079fb29ca83d3ac44b Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Mon, 6 Aug 2012 02:03:28 +0200 Subject: [PATCH 163/252] nfs4: Return delegations when asked to --- .../kernel/file_systems/nfs4/Delegation.cpp | 70 +++++++++++++++ .../kernel/file_systems/nfs4/Delegation.h | 21 ++++- .../kernel/file_systems/nfs4/FileInfo.h | 21 +++++ .../kernel/file_systems/nfs4/FileSystem.cpp | 42 +++++++++ .../kernel/file_systems/nfs4/FileSystem.h | 11 +++ .../kernel/file_systems/nfs4/Inode.cpp | 29 +++++++ src/add-ons/kernel/file_systems/nfs4/Inode.h | 3 + .../kernel/file_systems/nfs4/InodeRegular.cpp | 16 +++- src/add-ons/kernel/file_systems/nfs4/Jamfile | 3 + .../kernel/file_systems/nfs4/NFS4Defs.h | 5 ++ .../kernel/file_systems/nfs4/NFS4Server.cpp | 68 +++++++++++++++ .../kernel/file_systems/nfs4/NFS4Server.h | 8 ++ .../kernel/file_systems/nfs4/RPCCallback.cpp | 11 ++- .../kernel/file_systems/nfs4/RPCCallback.h | 4 + .../file_systems/nfs4/RPCCallbackRequest.cpp | 6 ++ .../file_systems/nfs4/RPCCallbackServer.cpp | 9 +- .../kernel/file_systems/nfs4/RPCServer.cpp | 2 +- .../kernel/file_systems/nfs4/RPCServer.h | 3 + .../kernel/file_systems/nfs4/ReplyBuilder.cpp | 85 +++++++++++++++++++ .../kernel/file_systems/nfs4/ReplyBuilder.h | 43 ++++++++++ .../file_systems/nfs4/ReplyInterpreter.h | 8 ++ .../file_systems/nfs4/RequestBuilder.cpp | 21 +++++ .../kernel/file_systems/nfs4/RequestBuilder.h | 1 + .../file_systems/nfs4/RequestInterpreter.cpp | 52 ++++++++++++ .../file_systems/nfs4/RequestInterpreter.h | 54 ++++++++++++ 25 files changed, 583 insertions(+), 13 deletions(-) create mode 100644 src/add-ons/kernel/file_systems/nfs4/Delegation.cpp create mode 100644 src/add-ons/kernel/file_systems/nfs4/ReplyBuilder.cpp create mode 100644 src/add-ons/kernel/file_systems/nfs4/ReplyBuilder.h create mode 100644 src/add-ons/kernel/file_systems/nfs4/RequestInterpreter.cpp create mode 100644 src/add-ons/kernel/file_systems/nfs4/RequestInterpreter.h diff --git a/src/add-ons/kernel/file_systems/nfs4/Delegation.cpp b/src/add-ons/kernel/file_systems/nfs4/Delegation.cpp new file mode 100644 index 0000000000..299cf2143e --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/Delegation.cpp @@ -0,0 +1,70 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ + + +#include "Delegation.h" + +#include "Inode.h" +#include "Request.h" + + +Delegation::Delegation(const OpenDelegationData& data, Inode* inode, + uint64 clientID) + : + fClientID(clientID), + fData(data), + fInode(inode) +{ + rw_lock_init(&fLock, NULL); +} + + +Delegation::~Delegation() +{ + rw_lock_destroy(&fLock); +} + +status_t +Delegation::GiveUp(bool truncate) +{ + if (!truncate) { + // save buffers + } + + ReturnDelegation(); + + return B_OK; +} + + +status_t +Delegation::ReturnDelegation() +{ + do { + RPC::Server* serv = fFileSystem->Server(); + Request request(serv); + RequestBuilder& req = request.Builder(); + + req.PutFH(fInfo.fHandle); + req.DelegReturn(fData.fStateID, fData.fStateSeq); + + 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.DelegReturn(); + } while (true); +} + diff --git a/src/add-ons/kernel/file_systems/nfs4/Delegation.h b/src/add-ons/kernel/file_systems/nfs4/Delegation.h index 31fea04344..d54da15a07 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Delegation.h +++ b/src/add-ons/kernel/file_systems/nfs4/Delegation.h @@ -15,9 +15,12 @@ #include "NFS4Object.h" -class Delegation : public NFS4Object { +class Inode; + +class Delegation : public NFS4Object, + public DoublyLinkedListLinkImpl { public: - Delegation(OpenDelegationData data, Inode* inode, + Delegation(const OpenDelegationData& data, Inode* inode, uint64 clientID); ~Delegation(); @@ -28,7 +31,12 @@ public: status_t Reclaim(uint64 newClientID); - status_t GiveUp(bool flush); + status_t GiveUp(bool truncate); + + inline Inode* GetInode(); + +protected: + status_t ReturnDelegation(); private: uint64 fClientID; @@ -39,5 +47,12 @@ private: }; +inline Inode* +Delegation::GetInode() +{ + return fInode; +} + + #endif // DELEGATION_H diff --git a/src/add-ons/kernel/file_systems/nfs4/FileInfo.h b/src/add-ons/kernel/file_systems/nfs4/FileInfo.h index 28b541218b..5cd0f2af3c 100644 --- a/src/add-ons/kernel/file_systems/nfs4/FileInfo.h +++ b/src/add-ons/kernel/file_systems/nfs4/FileInfo.h @@ -24,6 +24,9 @@ struct FileHandle { inline FileHandle(); inline FileHandle(const FileHandle& fh); inline FileHandle& operator=(const FileHandle& fh); + + inline bool operator>(const FileHandle& handle) const; + inline bool operator<(const FileHandle& handle) const; }; @@ -87,6 +90,24 @@ FileHandle::operator=(const FileHandle& fh) } +inline bool +FileHandle::operator>(const FileHandle& handle) const +{ + if (fSize > handle.fSize) + return true; + return memcmp(fData, handle.fData, fSize) > 0; +} + + +inline bool +FileHandle::operator<(const FileHandle& handle) const +{ + if (fSize < handle.fSize) + return true; + return memcmp(fData, handle.fData, fSize) < 0; +} + + inline FileInfo::FileInfo() : diff --git a/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp b/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp index f4eb9906d4..d5e3d8bf26 100644 --- a/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp @@ -38,6 +38,7 @@ FileSystem::FileSystem() mutex_init(&fOpenOwnerLock, NULL); mutex_init(&fOpenLock, NULL); + mutex_init(&fDelegationLock, NULL); } @@ -45,6 +46,7 @@ FileSystem::~FileSystem() { NFSServer()->RemoveFileSystem(this); + mutex_destroy(&fDelegationLock); mutex_destroy(&fOpenLock); mutex_destroy(&fOpenOwnerLock); @@ -308,3 +310,43 @@ FileSystem::RemoveOpenFile(OpenFileCookie* cookie) NFSServer()->DecUsage(); } + +void +FileSystem::AddDelegation(Delegation* delegation) +{ + MutexLocker _(fDelegationLock); + + fOpenDelegations.InsertBefore(fOpenDelegations.Head(), delegation); + + fHandleToDelegation.Remove(delegation->fInfo.fHandle); + fHandleToDelegation.Insert(delegation->fInfo.fHandle, delegation); + + NFSServer()->IncUsage(); +} + + +void +FileSystem::RemoveDelegation(Delegation* delegation) +{ + MutexLocker _(fDelegationLock); + + fOpenDelegations.Remove(delegation); + fHandleToDelegation.Remove(delegation->fInfo.fHandle); + + NFSServer()->DecUsage(); +} + + +Delegation* +FileSystem::GetDelegation(const FileHandle& handle) +{ + MutexLocker _(fDelegationLock); + + AVLTreeMap::Iterator it; + it = fHandleToDelegation.Find(handle); + if (!it.HasCurrent()) + return NULL; + + return it.Current(); +} + diff --git a/src/add-ons/kernel/file_systems/nfs4/FileSystem.h b/src/add-ons/kernel/file_systems/nfs4/FileSystem.h index 4c5df282e4..7814f8e667 100644 --- a/src/add-ons/kernel/file_systems/nfs4/FileSystem.h +++ b/src/add-ons/kernel/file_systems/nfs4/FileSystem.h @@ -10,6 +10,7 @@ #include "CacheRevalidator.h" +#include "Delegation.h" #include "InodeIdMap.h" #include "NFS4Defs.h" #include "NFS4Server.h" @@ -35,6 +36,12 @@ public: void AddOpenFile(OpenFileCookie* cookie); void RemoveOpenFile(OpenFileCookie* cookie); + OpenFileCookie* DelegationsLock(); + void DelegationsUnlock(); + void AddDelegation(Delegation* delegation); + void RemoveDelegation(Delegation* delegation); + Delegation* GetDelegation(const FileHandle& handle); + inline CacheRevalidator& Revalidator(); inline bool IsAttrSupported(Attribute attr) const; @@ -62,6 +69,10 @@ private: CacheRevalidator fCacheRevalidator; + DoublyLinkedList fOpenDelegations; + mutex fDelegationLock; + AVLTreeMap fHandleToDelegation; + OpenFileCookie* fOpenFiles; uint32 fOpenCount; mutex fOpenLock; diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index a573f4989d..0f0846e7e8 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -23,11 +23,13 @@ Inode::Inode() : fCache(NULL), + fDelegation(NULL), fFileCache(NULL), fMaxFileSize(0), fOpenState(NULL), fWriteDirty(false) { + rw_lock_init(&fDelegationLock, NULL); mutex_init(&fStateLock, NULL); mutex_init(&fFileCacheLock, NULL); } @@ -121,12 +123,16 @@ Inode::CreateInode(FileSystem* fs, const FileInfo &fi, Inode** _inode) Inode::~Inode() { + if (fDelegation != NULL) + RecallDelegation(); + if (fFileCache != NULL) file_cache_delete(fFileCache); delete fCache; mutex_destroy(&fStateLock); mutex_destroy(&fFileCacheLock); + rw_lock_destroy(&fDelegationLock); } @@ -721,3 +727,26 @@ Inode::ChildAdded(const char* name, uint64 fileID, return fFileSystem->InoIdMap()->AddEntry(fi, FileIdToInoT(fileID)); } + +void +Inode::SetDelegation(Delegation* delegation) +{ + WriteLocker _(fDelegationLock); + fDelegation = delegation; + fFileSystem->AddDelegation(delegation); +} + + +void +Inode::RecallDelegation(bool truncate) +{ + WriteLocker _(fDelegationLock); + if (fDelegation == NULL) + return; + + fDelegation->GiveUp(truncate); + fFileSystem->RemoveDelegation(fDelegation); + delete fDelegation; + fDelegation = NULL; +} + diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h b/src/add-ons/kernel/file_systems/nfs4/Inode.h index a44c12b584..4c56e75289 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -34,6 +34,9 @@ public: inline uint64 MaxFileSize(); + void SetDelegation(Delegation* delegation); + void RecallDelegation(bool truncate = false); + status_t LookUp(const char* name, ino_t* id); status_t Access(int mode); diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp index 34ca35e1f8..920821548b 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp @@ -96,6 +96,8 @@ Inode::Open(int mode, OpenFileCookie* cookie) { MutexLocker _(fStateLock); + OpenDelegationData data; + data.fType = OPEN_DELEGATE_NONE; if (fOpenState == NULL) { OpenState* state = new OpenState; if (state == NULL) @@ -103,7 +105,7 @@ Inode::Open(int mode, OpenFileCookie* cookie) state->fInfo = fInfo; state->fFileSystem = fFileSystem; - status_t result = OpenFile(state, mode, NULL); + status_t result = OpenFile(state, mode, &data); if (result != B_OK) return result; @@ -112,7 +114,7 @@ Inode::Open(int mode, OpenFileCookie* cookie) int newMode = mode & O_RWMASK; int oldMode = fOpenState->fMode & O_RWMASK; if (oldMode != newMode && oldMode != O_RDWR) { - status_t result = OpenFile(fOpenState, O_RDWR, NULL); + status_t result = OpenFile(fOpenState, O_RDWR, &data); if (result != B_OK) return result; fOpenState->fMode = O_RDWR; @@ -128,6 +130,16 @@ Inode::Open(int mode, OpenFileCookie* cookie) fFileSystem->AddOpenFile(cookie); + if (data.fType != OPEN_DELEGATE_NONE) { + Delegation* delegation + = new(std::nothrow) Delegation(data, this, fOpenState->fClientID); + if (delegation != NULL) { + delegation->fInfo = fOpenState->fInfo; + delegation->fFileSystem = fFileSystem; + SetDelegation(delegation); + } + } + return B_OK; } diff --git a/src/add-ons/kernel/file_systems/nfs4/Jamfile b/src/add-ons/kernel/file_systems/nfs4/Jamfile index b6aeed821e..a3a41946f2 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Jamfile +++ b/src/add-ons/kernel/file_systems/nfs4/Jamfile @@ -7,6 +7,7 @@ KernelAddon nfs4 : CacheRevalidator.cpp Cookie.cpp Connection.cpp + Delegation.cpp DirectoryCache.cpp FileInfo.cpp FileSystem.cpp @@ -20,9 +21,11 @@ KernelAddon nfs4 : NFS4Object.cpp NFS4Server.cpp OpenState.cpp + ReplyBuilder.cpp ReplyInterpreter.cpp Request.cpp RequestBuilder.cpp + RequestInterpreter.cpp RootInode.cpp RPCAuth.cpp RPCCall.cpp diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h index 1887ee2430..c162462178 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h @@ -25,11 +25,16 @@ enum CallbackProcedure { CallbackProcCompound = 1 }; +enum CallbackOpcode { + OpCallbackRecall = 4 +}; + enum Opcode { OpAccess = 3, OpClose = 4, OpCommit = 5, OpCreate = 6, + OpDelegReturn = 8, OpGetAttr = 9, OpGetFH = 10, OpLink = 11, diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp index ec38c3af13..88fbce1041 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp @@ -315,3 +315,71 @@ NFS4Server::_RenewalThreadStart(void* ptr) return server->_Renewal(); } + +status_t +NFS4Server::ProcessCallback(RPC::CallbackRequest* request, + Connection* connection) +{ + RequestInterpreter req(request); + ReplyBuilder reply(request->XID()); + + status_t result; + uint32 count = req.OperationCount(); + + for (uint32 i = 0; i < count; i++) { + switch (req.Operation()) { + case OpCallbackRecall: + result = CallbackRecall(&req, &reply); + break; + default: + result = B_NOT_SUPPORTED; + } + + if (result != B_OK) + break; + } + + XDR::WriteStream& stream = reply.Reply()->Stream(); + connection->Send(stream.Buffer(), stream.Size()); + + return B_OK; +} + + +status_t +NFS4Server::CallbackRecall(RequestInterpreter* request, ReplyBuilder* reply) +{ + uint32 stateID[3]; + uint32 stateSeq; + bool truncate; + FileHandle handle; + + status_t result = request->Recall(&handle, truncate, &stateSeq, stateID); + if (result != B_OK) + return result; + + MutexLocker locker(fFSLock); + + Delegation* delegation = NULL; + FileSystem* current = fFileSystems; + while (current != NULL) { + delegation = current->GetDelegation(handle); + if (delegation != NULL) + break; + + current = current->fNext; + } + locker.Unlock(); + + if (delegation == NULL) { + reply->Recall(B_FILE_NOT_FOUND); + return B_FILE_NOT_FOUND; + } + + // TODO: should be asynchronous + delegation->GetInode()->RecallDelegation(truncate); + + reply->Recall(B_OK); + return B_OK; +} + diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h index 46134e8b1b..4d37a960a8 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h @@ -11,6 +11,8 @@ #include +#include "ReplyBuilder.h" +#include "RequestInterpreter.h" #include "RPCServer.h" @@ -34,6 +36,12 @@ public: uint64 ClientId(uint64 prevId = 0, bool forceNew = false); inline uint32 LeaseTime(); + + virtual status_t ProcessCallback(RPC::CallbackRequest* request, + Connection* connection); + + status_t CallbackRecall(RequestInterpreter* request, + ReplyBuilder* reply); private: status_t _ReclaimOpen(OpenFileCookie* cookie); status_t _ReclaimLocks(OpenFileCookie* cookie); diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCCallback.cpp b/src/add-ons/kernel/file_systems/nfs4/RPCCallback.cpp index 70da61c58e..ddf5b63b01 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RPCCallback.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RPCCallback.cpp @@ -10,15 +10,22 @@ #include "RPCCallback.h" #include "RPCCallbackRequest.h" +#include "RPCServer.h" using namespace RPC; +Callback::Callback(Server* server) + : + fServer(server) +{ +} + + status_t Callback::EnqueueRequest(CallbackRequest* request, Connection* connection) { - dprintf("GOT A CALLBACK REQUEST %x\n", (int)request->XID()); - return B_OK; + return fServer->PrivateData()->ProcessCallback(request, connection); } diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCCallback.h b/src/add-ons/kernel/file_systems/nfs4/RPCCallback.h index 66d60ac116..b729156bd0 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RPCCallback.h +++ b/src/add-ons/kernel/file_systems/nfs4/RPCCallback.h @@ -15,9 +15,12 @@ namespace RPC { class CallbackRequest; +class Server; class Callback { public: + Callback(Server* server); + inline void SetID(int32 id); inline int32 ID(); @@ -25,6 +28,7 @@ public: Connection* connection); private: + Server* fServer; int32 fID; }; diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCCallbackRequest.cpp b/src/add-ons/kernel/file_systems/nfs4/RPCCallbackRequest.cpp index 4b10efb928..90fce4d550 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RPCCallbackRequest.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RPCCallbackRequest.cpp @@ -45,7 +45,10 @@ CallbackRequest::CallbackRequest(void *buffer, int size) fProcedure = fStream.GetUInt(); + fStream.GetUInt(); fStream.GetOpaque(NULL); + + fStream.GetUInt(); fStream.GetOpaque(NULL); if (fProcedure == CallbackProcCompound) { @@ -54,6 +57,9 @@ CallbackRequest::CallbackRequest(void *buffer, int size) return; fID = fStream.GetUInt(); + + fRPCError = SUCCESS; + fError = B_OK; } else if (fProcedure == CallbackProcNull) { fRPCError = SUCCESS; fError = B_OK; diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCCallbackServer.cpp b/src/add-ons/kernel/file_systems/nfs4/RPCCallbackServer.cpp index 5a64700092..b007a3ba99 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RPCCallbackServer.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RPCCallbackServer.cpp @@ -26,7 +26,7 @@ CallbackServer::CallbackServer() fConnectionList(NULL), fListener(NULL), fThreadRunning(false), - fCallbackArray(NULL), + //fCallbackArray(NULL), fArraySize(0), fFreeSlot(-1) { @@ -40,7 +40,7 @@ CallbackServer::~CallbackServer() { StopServer(); - free(fCallbackArray); + //free(fCallbackArray); rw_lock_destroy(&fArrayLock); mutex_destroy(&fThreadLock); mutex_destroy(&fConnectionLock); @@ -68,7 +68,7 @@ CallbackServer::RegisterCallback(Callback* callback) for (uint32 i = fArraySize; i < newSize; i++) array[i].fNext = i + 1; - array[fArraySize * 2 - 1].fNext = -1; + array[newSize - 1].fNext = -1; fCallbackArray = array; fFreeSlot = fArraySize; @@ -240,7 +240,7 @@ CallbackServer::ConnectionThread(ConnectionEntry* entry) if (request == NULL || request->Error() != B_OK) { free(buffer); continue; - } else if (request != NULL) { + } else if (request != NULL && request->Error() != B_OK) { reply = CallbackReply::Create(request->XID(), request->RPCError()); if (reply != NULL) { connection->Send(reply->Stream().Buffer(), @@ -251,7 +251,6 @@ CallbackServer::ConnectionThread(ConnectionEntry* entry) continue; } - switch (request->Procedure()) { case CallbackProcCompound: GetCallback(request->ID())->EnqueueRequest(request, connection); diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp b/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp index fce6f5aa3b..70876f6682 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp @@ -228,7 +228,7 @@ Server::GetCallback() { MutexLocker _(fCallbackLock); if (fCallback == NULL) { - fCallback = new Callback; + fCallback = new(std::nothrow) Callback(this); gRPCCallbackServer->RegisterCallback(fCallback); } diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCServer.h b/src/add-ons/kernel/file_systems/nfs4/RPCServer.h index ddcb80e423..f4afd7f02e 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RPCServer.h +++ b/src/add-ons/kernel/file_systems/nfs4/RPCServer.h @@ -48,6 +48,9 @@ private: class ProgramData { public: + virtual status_t ProcessCallback(CallbackRequest* request, + Connection* connection) = 0; + virtual ~ProgramData() { } }; diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyBuilder.cpp b/src/add-ons/kernel/file_systems/nfs4/ReplyBuilder.cpp new file mode 100644 index 0000000000..e18a4a64ad --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyBuilder.cpp @@ -0,0 +1,85 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ + + +#include "ReplyBuilder.h" + +#include "NFS4Defs.h" +#include "RPCCallbackReply.h" + + +ReplyBuilder::ReplyBuilder(uint32 xid) + : + fStatus(B_OK), + fOpCount(0), + fReply(RPC::CallbackReply::Create(xid)) +{ + _InitHeader(); +} + + +ReplyBuilder::~ReplyBuilder() +{ + delete fReply; +} + + +void +ReplyBuilder::_InitHeader() +{ + fStatusPosition = fReply->Stream().Current(); + fReply->Stream().AddUInt(0); + + fReply->Stream().AddOpaque(NULL, 0); + + fOpCountPosition = fReply->Stream().Current(); + fReply->Stream().AddUInt(0); + +} + + +RPC::CallbackReply* +ReplyBuilder::Reply() +{ + fReply->Stream().InsertUInt(fStatusPosition, _HaikuErrorToNFS4(fStatus)); + fReply->Stream().InsertUInt(fOpCountPosition, fOpCount); + + if (fReply == NULL || fReply->Stream().Error() == B_OK) + return fReply; + else + return NULL; +} + + +status_t +ReplyBuilder::Recall(status_t status) +{ + if (fStatus != B_OK) + return B_ERROR; + + fReply->Stream().AddUInt(OpCallbackRecall); + fReply->Stream().AddUInt(_HaikuErrorToNFS4(fStatus)); + fStatus = status; + + fOpCount++; + + return B_OK; +} + + +uint32 +ReplyBuilder::_HaikuErrorToNFS4(status_t error) +{ + switch (error) { + case B_OK: return NFS4_OK; + case B_FILE_NOT_FOUND: return NFS4ERR_BADHANDLE; + case B_NOT_SUPPORTED: return NFS4ERR_OP_ILLEGAL; + default: return NFS4ERR_RESOURCE; + } +} + diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyBuilder.h b/src/add-ons/kernel/file_systems/nfs4/ReplyBuilder.h new file mode 100644 index 0000000000..be85416261 --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyBuilder.h @@ -0,0 +1,43 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ +#ifndef REPLYBUILDER_H +#define REPLYBUILDER_H + + +#include + +#include "RPCCallbackReply.h" +#include "XDR.h" + + +class ReplyBuilder { +public: + ReplyBuilder(uint32 xid); + ~ReplyBuilder(); + + RPC::CallbackReply* Reply(); + + status_t Recall(status_t status); + +private: + void _InitHeader(); + + static uint32 _HaikuErrorToNFS4(status_t error); + + status_t fStatus; + XDR::Stream::Position fStatusPosition; + + uint32 fOpCount; + XDR::Stream::Position fOpCountPosition; + + RPC::CallbackReply* fReply; +}; + + +#endif // REPLYBUILDER_H + diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h index 892e34cc41..986fcd8a7c 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h @@ -71,6 +71,7 @@ public: status_t Close(); status_t Commit(); status_t Create(uint64* before, uint64* after, bool& atomic); + inline status_t DelegReturn(); status_t GetAttr(AttrValue** attrs, uint32* count); status_t GetFH(FileHandle* fh); status_t Link(uint64* before, uint64* after, bool& atomic); @@ -150,6 +151,13 @@ ReplyInterpreter::NFS4Error() } +inline status_t +ReplyInterpreter::DelegReturn() +{ + return _OperationError(OpDelegReturn); +} + + inline status_t ReplyInterpreter::LookUp() { diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp index c05b873a11..17d825946b 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp @@ -137,6 +137,27 @@ RequestBuilder::Create(FileType type, const char* name, AttrValue* attr, } +status_t +RequestBuilder::DelegReturn(const uint32* id, uint32 seq) +{ + if (fProcedure != ProcCompound) + return B_BAD_VALUE; + if (fRequest == NULL) + return B_NO_MEMORY; + + fRequest->Stream().AddUInt(OpDelegReturn); + + fRequest->Stream().AddUInt(seq); + fRequest->Stream().AddUInt(id[0]); + fRequest->Stream().AddUInt(id[1]); + fRequest->Stream().AddUInt(id[2]); + + fOpCount++; + + return B_OK; +} + + status_t RequestBuilder::GetAttr(Attribute* attrs, uint32 count) { diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h index 13db57de2b..d850c3c176 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h @@ -37,6 +37,7 @@ public: status_t Create(FileType type, const char* name, AttrValue* attr, uint32 count, const char* path = NULL); + status_t DelegReturn(const uint32* id, uint32 seq); status_t GetAttr(Attribute* attrs, uint32 count); status_t GetFH(); status_t Link(const char* name); diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestInterpreter.cpp b/src/add-ons/kernel/file_systems/nfs4/RequestInterpreter.cpp new file mode 100644 index 0000000000..c129cde78d --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/RequestInterpreter.cpp @@ -0,0 +1,52 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ + + +#include "RequestInterpreter.h" + +#include + +#include + + +RequestInterpreter::RequestInterpreter(RPC::CallbackRequest* request) + : + fRequest(request) +{ + fOperationCount = fRequest->Stream().GetUInt(); +} + + +RequestInterpreter::~RequestInterpreter() +{ + delete fRequest; +} + + +status_t +RequestInterpreter::Recall(FileHandle* handle, bool& truncate, uint32* stateSeq, + uint32* stateID) +{ + if (fLastOperation != OpCallbackRecall) + return B_BAD_VALUE; + + *stateSeq = fRequest->Stream().GetUInt(); + stateID[0] = fRequest->Stream().GetUInt(); + stateID[1] = fRequest->Stream().GetUInt(); + stateID[2] = fRequest->Stream().GetUInt(); + + truncate = fRequest->Stream().GetBoolean(); + + uint32 size; + const void* ptr = fRequest->Stream().GetOpaque(&size); + handle->fSize = size; + memcpy(handle->fData, ptr, size); + + return fRequest->Stream().IsEOF() ? B_BAD_VALUE : B_OK; +} + diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestInterpreter.h b/src/add-ons/kernel/file_systems/nfs4/RequestInterpreter.h new file mode 100644 index 0000000000..5febb48399 --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/RequestInterpreter.h @@ -0,0 +1,54 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ +#ifndef REQUESTINTERPRETER_H +#define REQUESTINTERPRETER_H + + +#include + +#include "FileInfo.h" +#include "NFS4Defs.h" +#include "RPCCallbackRequest.h" + + +class RequestInterpreter { +public: + RequestInterpreter(RPC::CallbackRequest* request); + ~RequestInterpreter(); + + inline uint32 OperationCount(); + inline uint32 Operation(); + + status_t Recall(FileHandle* handle, bool& truncate, + uint32* stateSeq, uint32* stateID); + +private: + uint32 fOperationCount; + uint32 fLastOperation; + + RPC::CallbackRequest* fRequest; +}; + + +inline uint32 +RequestInterpreter::OperationCount() +{ + return fOperationCount; +} + + +inline uint32 +RequestInterpreter::Operation() +{ + fLastOperation = fRequest->Stream().GetUInt(); + return fLastOperation; +} + + +#endif // REQUESTINTERPRETER_H + From bfa20379a3d5756dda6f3ebab0dcf52b6f4ca749 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Mon, 6 Aug 2012 03:18:46 +0200 Subject: [PATCH 164/252] nfs4: Reclaim delegations after server reboot --- .../kernel/file_systems/nfs4/Cookie.cpp | 92 ++-------- src/add-ons/kernel/file_systems/nfs4/Cookie.h | 21 +-- .../kernel/file_systems/nfs4/Delegation.h | 15 +- .../kernel/file_systems/nfs4/FileSystem.cpp | 29 ++-- .../kernel/file_systems/nfs4/FileSystem.h | 11 +- .../kernel/file_systems/nfs4/Inode.cpp | 60 +++++-- .../kernel/file_systems/nfs4/InodeRegular.cpp | 14 +- .../kernel/file_systems/nfs4/NFS4Inode.cpp | 4 +- .../kernel/file_systems/nfs4/NFS4Object.cpp | 1 + .../kernel/file_systems/nfs4/NFS4Server.cpp | 56 +----- .../kernel/file_systems/nfs4/NFS4Server.h | 3 - .../kernel/file_systems/nfs4/OpenState.cpp | 160 +++++++++++++++++- .../kernel/file_systems/nfs4/OpenState.h | 22 +++ .../file_systems/nfs4/RequestBuilder.cpp | 25 ++- .../kernel/file_systems/nfs4/RequestBuilder.h | 18 +- 15 files changed, 308 insertions(+), 223 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Cookie.cpp b/src/add-ons/kernel/file_systems/nfs4/Cookie.cpp index a2970b7a95..23a38e2950 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Cookie.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Cookie.cpp @@ -57,6 +57,14 @@ LockInfo::operator==(const struct flock& lock) const } +bool +LockInfo::operator==(const LockInfo& lock) const +{ + return fOwner == lock.fOwner && fStart == lock.fStart + && fLength == lock.fLength && fType == lock.fType; +} + + Cookie::Cookie() : fRequests(NULL), @@ -131,102 +139,26 @@ Cookie::CancelAll() OpenFileCookie::OpenFileCookie() : - fLocks(NULL), - fLockOwners(NULL) + fLocks(NULL) { - mutex_init(&fLocksLock, NULL); - mutex_init(&fOwnerLock, NULL); } -OpenFileCookie::~OpenFileCookie() -{ - mutex_destroy(&fLocksLock); - mutex_destroy(&fOwnerLock); -} - - -LockOwner* -OpenFileCookie::GetLockOwner(uint32 owner) -{ - LockOwner* current = fLockOwners; - while (current != NULL) { - if (current->fOwner == owner) - return current; - - current = current->fNext; - } - - current = new LockOwner(owner); - if (current == NULL) - return NULL; - - current->fNext = fLockOwners; - if (fLockOwners != NULL) - fLockOwners->fPrev = current; - fLockOwners = current; - - return current; -} - - -// Caller must hold fLocksLock void OpenFileCookie::AddLock(LockInfo* lock) { - lock->fNext = fLocks; + lock->fCookieNext = fLocks; fLocks = lock; } -// Caller must hold fLocksLock void OpenFileCookie::RemoveLock(LockInfo* lock, LockInfo* prev) { if (prev != NULL) - prev->fNext = lock->fNext; + prev->fCookieNext = lock->fCookieNext; else - fLocks = lock->fNext; -} - - -void -OpenFileCookie::DeleteLock(LockInfo* lock) -{ - MutexLocker _(fOwnerLock); - - LockOwner* owner = lock->fOwner; - delete lock; - - if (owner->fUseCount == 0) { - if (owner->fPrev) - owner->fPrev->fNext = owner->fNext; - else - fLockOwners = owner->fNext; - if (owner->fNext) - owner->fNext->fPrev = owner->fPrev; - - _ReleaseLockOwner(owner); - delete owner; - } -} - - -status_t -OpenFileCookie::_ReleaseLockOwner(LockOwner* owner) -{ - Request request(fFileSystem->Server()); - RequestBuilder& req = request.Builder(); - - req.ReleaseLockOwner(this, owner); - - status_t result = request.Send(); - if (result != B_OK) - return result; - - ReplyInterpreter &reply = request.Reply(); - - return reply.ReleaseLockOwner(); + fLocks = lock->fCookieNext; } diff --git a/src/add-ons/kernel/file_systems/nfs4/Cookie.h b/src/add-ons/kernel/file_systems/nfs4/Cookie.h index 4af8899333..1fd8c9c29a 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Cookie.h +++ b/src/add-ons/kernel/file_systems/nfs4/Cookie.h @@ -12,9 +12,10 @@ #include #include "FileSystem.h" -#include "OpenState.h" +struct OpenState; + struct LockOwner { uint64 fClientId; @@ -43,11 +44,13 @@ struct LockInfo { LockType fType; LockInfo* fNext; + LockInfo* fCookieNext; LockInfo(LockOwner* owner); ~LockInfo(); bool operator==(const struct flock& lock) const; + bool operator==(const LockInfo& lock) const; }; struct Cookie { @@ -76,25 +79,11 @@ struct OpenFileCookie : public Cookie { uint32 fMode; LockInfo* fLocks; - mutex fLocksLock; - - LockOwner* fLockOwners; - mutex fOwnerLock; - - OpenFileCookie* fNext; - OpenFileCookie* fPrev; - - OpenFileCookie(); - ~OpenFileCookie(); - - LockOwner* GetLockOwner(uint32 owner); void AddLock(LockInfo* lock); void RemoveLock(LockInfo* lock, LockInfo* prev); - void DeleteLock(LockInfo* lock); -private: - status_t _ReleaseLockOwner(LockOwner* owner); + OpenFileCookie(); }; struct OpenDirCookie : public Cookie { diff --git a/src/add-ons/kernel/file_systems/nfs4/Delegation.h b/src/add-ons/kernel/file_systems/nfs4/Delegation.h index d54da15a07..27099e2281 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Delegation.h +++ b/src/add-ons/kernel/file_systems/nfs4/Delegation.h @@ -24,16 +24,12 @@ public: uint64 clientID); ~Delegation(); - status_t Write(void* buffer, uint32* size); - status_t Read(void* buffer, uint32* size); - // TODO: locks - status_t Reclaim(uint64 newClientID); - - status_t GiveUp(bool truncate); + status_t GiveUp(bool truncate = false); inline Inode* GetInode(); + inline OpenDelegation Type(); protected: status_t ReturnDelegation(); @@ -54,5 +50,12 @@ Delegation::GetInode() } +inline OpenDelegation +Delegation::Type() +{ + return fData.fType; +} + + #endif // DELEGATION_H diff --git a/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp b/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp index d5e3d8bf26..9379f3e638 100644 --- a/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp @@ -267,7 +267,7 @@ FileSystem::Migrate(const RPC::Server* serv) } -OpenFileCookie* +OpenState* FileSystem::OpenFilesLock() { mutex_lock(&fOpenLock); @@ -283,30 +283,30 @@ FileSystem::OpenFilesUnlock() void -FileSystem::AddOpenFile(OpenFileCookie* cookie) +FileSystem::AddOpenFile(OpenState* state) { MutexLocker _(fOpenLock); - cookie->fPrev = NULL; - cookie->fNext = fOpenFiles; + state->fPrev = NULL; + state->fNext = fOpenFiles; if (fOpenFiles != NULL) - fOpenFiles->fPrev = cookie; - fOpenFiles = cookie; + fOpenFiles->fPrev = state; + fOpenFiles = state; NFSServer()->IncUsage(); } void -FileSystem::RemoveOpenFile(OpenFileCookie* cookie) +FileSystem::RemoveOpenFile(OpenState* state) { MutexLocker _(fOpenLock); - if (cookie == fOpenFiles) - fOpenFiles = cookie->fNext; + if (state == fOpenFiles) + fOpenFiles = state->fNext; - if (cookie->fNext) - cookie->fNext->fPrev = cookie->fPrev; - if (cookie->fPrev) - cookie->fPrev->fNext = cookie->fNext; + if (state->fNext) + state->fNext->fPrev = state->fPrev; + if (state->fPrev) + state->fPrev->fNext = state->fNext; NFSServer()->DecUsage(); } @@ -316,8 +316,6 @@ FileSystem::AddDelegation(Delegation* delegation) { MutexLocker _(fDelegationLock); - fOpenDelegations.InsertBefore(fOpenDelegations.Head(), delegation); - fHandleToDelegation.Remove(delegation->fInfo.fHandle); fHandleToDelegation.Insert(delegation->fInfo.fHandle, delegation); @@ -330,7 +328,6 @@ FileSystem::RemoveDelegation(Delegation* delegation) { MutexLocker _(fDelegationLock); - fOpenDelegations.Remove(delegation); fHandleToDelegation.Remove(delegation->fInfo.fHandle); NFSServer()->DecUsage(); diff --git a/src/add-ons/kernel/file_systems/nfs4/FileSystem.h b/src/add-ons/kernel/file_systems/nfs4/FileSystem.h index 7814f8e667..0bd634dd6e 100644 --- a/src/add-ons/kernel/file_systems/nfs4/FileSystem.h +++ b/src/add-ons/kernel/file_systems/nfs4/FileSystem.h @@ -30,14 +30,12 @@ public: status_t Migrate(const RPC::Server* serv); - OpenFileCookie* OpenFilesLock(); + OpenState* OpenFilesLock(); void OpenFilesUnlock(); inline uint32 OpenFilesCount(); - void AddOpenFile(OpenFileCookie* cookie); - void RemoveOpenFile(OpenFileCookie* cookie); + void AddOpenFile(OpenState* state); + void RemoveOpenFile(OpenState* state); - OpenFileCookie* DelegationsLock(); - void DelegationsUnlock(); void AddDelegation(Delegation* delegation); void RemoveDelegation(Delegation* delegation); Delegation* GetDelegation(const FileHandle& handle); @@ -69,11 +67,10 @@ private: CacheRevalidator fCacheRevalidator; - DoublyLinkedList fOpenDelegations; mutex fDelegationLock; AVLTreeMap fHandleToDelegation; - OpenFileCookie* fOpenFiles; + OpenState* fOpenFiles; uint32 fOpenCount; mutex fOpenLock; diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index 0f0846e7e8..e56fdc9998 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -607,6 +607,8 @@ status_t Inode::AcquireLock(OpenFileCookie* cookie, const struct flock* lock, bool wait) { + OpenState* state = cookie->fOpenState; + status_t result = CheckLockType(lock->l_type, cookie->fMode); if (result != B_OK) return result; @@ -614,8 +616,8 @@ Inode::AcquireLock(OpenFileCookie* cookie, const struct flock* lock, thread_info info; get_thread_info(find_thread(NULL), &info); - MutexLocker locker(cookie->fOwnerLock); - LockOwner* owner = cookie->GetLockOwner(info.team); + MutexLocker locker(state->fOwnerLock); + LockOwner* owner = state->GetLockOwner(info.team); if (owner == NULL) return B_NO_MEMORY; @@ -635,7 +637,8 @@ Inode::AcquireLock(OpenFileCookie* cookie, const struct flock* lock, if (result != B_OK) return result; - MutexLocker _(cookie->fLocksLock); + MutexLocker _(state->fLocksLock); + state->AddLock(linfo); cookie->AddLock(linfo); return B_OK; @@ -654,8 +657,21 @@ Inode::ReleaseLock(OpenFileCookie* cookie, const struct flock* lock) get_thread_info(find_thread(NULL), &info); uint32 owner = info.team; - MutexLocker locker(cookie->fLocksLock); - LockInfo* linfo = cookie->fLocks; + OpenState* state = cookie->fOpenState; + MutexLocker locker(state->fLocksLock); + LockInfo* linfo = state->fLocks; + while (linfo != NULL) { + if (linfo->fOwner->fOwner == owner && *linfo == *lock) { + state->RemoveLock(linfo, prev); + break; + } + + prev = linfo; + linfo = linfo->fNext; + } + + prev = NULL; + linfo = cookie->fLocks; while (linfo != NULL) { if (linfo->fOwner->fOwner == owner && *linfo == *lock) { cookie->RemoveLock(linfo, prev); @@ -663,7 +679,7 @@ Inode::ReleaseLock(OpenFileCookie* cookie, const struct flock* lock) } prev = linfo; - linfo = linfo->fNext; + linfo = linfo->fCookieNext; } locker.Unlock(); @@ -674,7 +690,7 @@ Inode::ReleaseLock(OpenFileCookie* cookie, const struct flock* lock) if (result != B_OK) return result; - cookie->DeleteLock(linfo); + state->DeleteLock(linfo); return B_OK; } @@ -686,12 +702,26 @@ Inode::ReleaseAllLocks(OpenFileCookie* cookie) file_cache_sync(fFileCache); Commit(); - MutexLocker _(cookie->fLocksLock); + OpenState* state = cookie->fOpenState; + MutexLocker _(state->fLocksLock); LockInfo* linfo = cookie->fLocks; while (linfo != NULL) { - NFS4Inode::ReleaseLock(cookie, linfo); cookie->RemoveLock(linfo, NULL); - cookie->DeleteLock(linfo); + + LockInfo* prev = NULL; + LockInfo* stateLock = state->fLocks; + while (stateLock != NULL) { + if (*linfo == *stateLock) { + state->RemoveLock(stateLock, prev); + break; + } + + prev = stateLock; + stateLock = stateLock->fNext; + } + + NFS4Inode::ReleaseLock(cookie, linfo); + state->DeleteLock(linfo); linfo = cookie->fLocks; } @@ -733,6 +763,8 @@ Inode::SetDelegation(Delegation* delegation) { WriteLocker _(fDelegationLock); fDelegation = delegation; + fOpenState->AcquireReference(); + fOpenState->fDelegation = delegation; fFileSystem->AddDelegation(delegation); } @@ -746,6 +778,14 @@ Inode::RecallDelegation(bool truncate) fDelegation->GiveUp(truncate); fFileSystem->RemoveDelegation(fDelegation); + + MutexLocker stateLocker(fStateLock); + fOpenState->fDelegation = NULL; + if (fOpenState->ReleaseReference() == 1) { + fFileSystem->RemoveOpenFile(fOpenState); + fOpenState = NULL; + } + delete fDelegation; fDelegation = NULL; } diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp index 920821548b..76e4820af7 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp @@ -84,7 +84,7 @@ Inode::Create(const char* name, int mode, int perms, OpenFileCookie* cookie, cookie->fFileSystem = fFileSystem; - fFileSystem->AddOpenFile(cookie); + fFileSystem->AddOpenFile(state); fFileSystem->Root()->MakeInfoInvalid(); return B_OK; @@ -109,6 +109,7 @@ Inode::Open(int mode, OpenFileCookie* cookie) if (result != B_OK) return result; + fFileSystem->AddOpenFile(state); fOpenState = state; } else { int newMode = mode & O_RWMASK; @@ -128,8 +129,6 @@ Inode::Open(int mode, OpenFileCookie* cookie) cookie->fMode = mode; cookie->fLocks = NULL; - fFileSystem->AddOpenFile(cookie); - if (data.fType != OPEN_DELEGATE_NONE) { Delegation* delegation = new(std::nothrow) Delegation(data, this, fOpenState->fClientID); @@ -150,12 +149,13 @@ Inode::Close(OpenFileCookie* cookie) file_cache_sync(fFileCache); Commit(); - fFileSystem->RemoveOpenFile(cookie); - MutexLocker _(fStateLock); - if (cookie->fOpenState != NULL) - if (cookie->fOpenState->ReleaseReference() == 1) + if (cookie->fOpenState != NULL) { + if (cookie->fOpenState->ReleaseReference() == 1) { + fFileSystem->RemoveOpenFile(fOpenState); fOpenState = NULL; + } + } return B_OK; } diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp index c2208fb8af..e45f08f4f2 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp @@ -879,7 +879,7 @@ NFS4Inode::TestLock(OpenFileCookie* cookie, LockType* type, uint64* position, RequestBuilder& req = request.Builder(); req.PutFH(fInfo.fHandle); - req.LockT(*type, *position, *length, cookie); + req.LockT(*type, *position, *length, cookie->fOpenState); status_t result = request.Send(); if (result != B_OK) @@ -916,7 +916,7 @@ NFS4Inode::AcquireLock(OpenFileCookie* cookie, LockInfo* lockInfo, bool wait) RequestBuilder& req = request.Builder(); req.PutFH(fInfo.fHandle); - req.Lock(cookie, lockInfo, sequence); + req.Lock(cookie->fOpenState, lockInfo, sequence); status_t result = request.Send(); if (result != B_OK) { diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp index 327c075246..192e691f00 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp @@ -10,6 +10,7 @@ #include "Cookie.h" #include "FileSystem.h" #include "NFS4Object.h" +#include "OpenState.h" #include "Request.h" diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp index 88fbce1041..05c85035f5 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp @@ -57,13 +57,14 @@ NFS4Server::ServerRebooted(uint64 clientId) MutexLocker _(fFSLock); FileSystem* fs = fFileSystems; while (fs != NULL) { - OpenFileCookie* current = fs->OpenFilesLock(); + OpenState* current = fs->OpenFilesLock(); while (current != NULL) { - _ReclaimOpen(current); - _ReclaimLocks(current); + current->Reclaim(fClientId); + current = current->fNext; } fs->OpenFilesUnlock(); + fs = fs->fNext; } @@ -71,55 +72,6 @@ NFS4Server::ServerRebooted(uint64 clientId) } -status_t -NFS4Server::_ReclaimOpen(OpenFileCookie* cookie) -{ - if (cookie->fOpenState != NULL) - cookie->fOpenState->Reclaim(fClientId); - - return B_OK; -} - - -status_t -NFS4Server::_ReclaimLocks(OpenFileCookie* cookie) -{ - MutexLocker _(cookie->fLocksLock); - LockInfo* linfo = cookie->fLocks; - while (linfo != NULL) { - MutexLocker locker(linfo->fOwner->fLock); - if (linfo->fOwner->fClientId != fClientId) { - memset(linfo->fOwner->fStateId, 0, sizeof(linfo->fOwner->fStateId)); - linfo->fOwner->fClientId = fClientId; - } - - do { - Request request(fServer); - RequestBuilder& req = request.Builder(); - - req.PutFH(cookie->fOpenState->fInfo.fHandle); - req.Lock(cookie, linfo, true); - - status_t result = request.Send(); - if (result != B_OK) - break; - - ReplyInterpreter &reply = request.Reply(); - - reply.PutFH(); - reply.Lock(linfo); - - break; - } while (true); - locker.Unlock(); - - linfo = linfo->fNext; - } - - return B_OK; -} - - void NFS4Server::AddFileSystem(FileSystem* fs) { diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h index 4d37a960a8..d312018e21 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h @@ -43,9 +43,6 @@ public: status_t CallbackRecall(RequestInterpreter* request, ReplyBuilder* reply); private: - status_t _ReclaimOpen(OpenFileCookie* cookie); - status_t _ReclaimLocks(OpenFileCookie* cookie); - status_t _GetLeaseTime(); status_t _StartRenewing(); diff --git a/src/add-ons/kernel/file_systems/nfs4/OpenState.cpp b/src/add-ons/kernel/file_systems/nfs4/OpenState.cpp index 236ff7c243..388b62fc8e 100644 --- a/src/add-ons/kernel/file_systems/nfs4/OpenState.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/OpenState.cpp @@ -17,9 +17,15 @@ OpenState::OpenState() : - fOpened(false) + fOpened(false), + fDelegation(NULL), + fLocks(NULL), + fLockOwners(NULL) { mutex_init(&fLock, NULL); + + mutex_init(&fLocksLock, NULL); + mutex_init(&fOwnerLock, NULL); } @@ -27,6 +33,99 @@ OpenState::~OpenState() { Close(); mutex_destroy(&fLock); + + mutex_destroy(&fLocksLock); + mutex_destroy(&fOwnerLock); +} + + +LockOwner* +OpenState::GetLockOwner(uint32 owner) +{ + LockOwner* current = fLockOwners; + while (current != NULL) { + if (current->fOwner == owner) + return current; + + current = current->fNext; + } + + current = new LockOwner(owner); + if (current == NULL) + return NULL; + + current->fNext = fLockOwners; + if (fLockOwners != NULL) + fLockOwners->fPrev = current; + fLockOwners = current; + + return current; +} + + +// Caller must hold fLocksLock +void +OpenState::AddLock(LockInfo* lock) +{ + lock->fNext = fLocks; + fLocks = lock; +} + + +// Caller must hold fLocksLock +void +OpenState::RemoveLock(LockInfo* lock, LockInfo* prev) +{ + if (prev != NULL) + prev->fNext = lock->fNext; + else + fLocks = lock->fNext; +} + + +void +OpenState::DeleteLock(LockInfo* lock) +{ + MutexLocker _(fOwnerLock); + + LockOwner* owner = lock->fOwner; + delete lock; + + if (owner->fUseCount == 0) { + if (owner->fPrev) + owner->fPrev->fNext = owner->fNext; + else + fLockOwners = owner->fNext; + if (owner->fNext) + owner->fNext->fPrev = owner->fPrev; + + _ReleaseLockOwner(owner); + delete owner; + } +} + + +status_t +OpenState::_ReleaseLockOwner(LockOwner* owner) +{ + do { + RPC::Server* server = fFileSystem->Server(); + Request request(server); + RequestBuilder& req = request.Builder(); + + req.ReleaseLockOwner(this, owner); + + status_t result = request.Send(); + if (result != B_OK) + return result; + + ReplyInterpreter &reply = request.Reply(); + + if (HandleErrors(reply.NFS4Error(), server)) + continue; + + return reply.ReleaseLockOwner(); + } while (true); } @@ -42,6 +141,15 @@ OpenState::Reclaim(uint64 newClientID) return B_OK; fClientID = newClientID; + _ReclaimOpen(newClientID); + _ReclaimLocks(newClientID); + return B_OK; +} + + +status_t +OpenState::_ReclaimOpen(uint64 newClientID) +{ bool confirm; OpenDelegationData delegation; @@ -53,7 +161,8 @@ OpenState::Reclaim(uint64 newClientID) req.PutFH(fInfo.fHandle); req.Open(CLAIM_PREVIOUS, sequence, sModeToAccess(fMode), newClientID, - OPEN4_NOCREATE, fFileSystem->OpenOwner(), NULL); + OPEN4_NOCREATE, fFileSystem->OpenOwner(), NULL, NULL, 0, false, + fDelegation->Type()); status_t result = request.Send(); if (result != B_OK) { @@ -75,6 +184,9 @@ OpenState::Reclaim(uint64 newClientID) return result; } while (true); + if (delegation.fRecall) + fDelegation->GiveUp(); + if (confirm) return ConfirmOpen(fInfo.fHandle, this); @@ -82,6 +194,50 @@ OpenState::Reclaim(uint64 newClientID) } +status_t +OpenState::_ReclaimLocks(uint64 newClientID) +{ + MutexLocker _(fLocksLock); + LockInfo* linfo = fLocks; + while (linfo != NULL) { + MutexLocker locker(linfo->fOwner->fLock); + + if (linfo->fOwner->fClientId != newClientID) { + memset(linfo->fOwner->fStateId, 0, sizeof(linfo->fOwner->fStateId)); + linfo->fOwner->fClientId = newClientID; + } + + do { + RPC::Server* server = fFileSystem->Server(); + Request request(server); + RequestBuilder& req = request.Builder(); + + req.PutFH(fInfo.fHandle); + req.Lock(this, linfo, true); + + status_t result = request.Send(); + if (result != B_OK) + break; + + ReplyInterpreter &reply = request.Reply(); + + if (HandleErrors(reply.NFS4Error(), server)) + continue; + + reply.PutFH(); + reply.Lock(linfo); + + break; + } while (true); + locker.Unlock(); + + linfo = linfo->fNext; + } + + return B_OK; +} + + status_t OpenState::Close() { diff --git a/src/add-ons/kernel/file_systems/nfs4/OpenState.h b/src/add-ons/kernel/file_systems/nfs4/OpenState.h index ecf10a8a41..8cfdce5253 100644 --- a/src/add-ons/kernel/file_systems/nfs4/OpenState.h +++ b/src/add-ons/kernel/file_systems/nfs4/OpenState.h @@ -13,6 +13,7 @@ #include #include +#include "Cookie.h" #include "NFS4Object.h" @@ -29,10 +30,31 @@ struct OpenState : public NFS4Object, public KernelReferenceable { uint32 fStateSeq; bool fOpened; + Delegation* fDelegation; + + LockInfo* fLocks; + mutex fLocksLock; + + LockOwner* fLockOwners; + mutex fOwnerLock; + + OpenState* fNext; + OpenState* fPrev; + + LockOwner* GetLockOwner(uint32 owner); + + void AddLock(LockInfo* lock); + void RemoveLock(LockInfo* lock, LockInfo* prev); + void DeleteLock(LockInfo* lock); status_t Reclaim(uint64 newClientID); status_t Close(); + +private: + status_t _ReclaimOpen(uint64 newClientID); + status_t _ReclaimLocks(uint64 newClientID); + status_t _ReleaseLockOwner(LockOwner* owner); }; diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp index 17d825946b..08f4dff29c 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp @@ -13,6 +13,7 @@ #include #include "Cookie.h" +#include "OpenState.h" #include "RPCCallback.h" #include "RPCCallbackServer.h" @@ -192,19 +193,19 @@ RequestBuilder::GetFH() void RequestBuilder::_GenerateLockOwner(XDR::WriteStream& stream, - OpenFileCookie* cookie, LockOwner* owner) + OpenState* state, LockOwner* owner) { - stream.AddUHyper(cookie->fOpenState->fClientID); + stream.AddUHyper(state->fClientID); uint64 lockOwner[2]; lockOwner[0] = owner->fOwner; - lockOwner[1] = cookie->fOpenState->fInfo.fFileId; + lockOwner[1] = state->fInfo.fFileId; stream.AddOpaque(lockOwner, sizeof(lockOwner)); } status_t -RequestBuilder::Lock(OpenFileCookie* cookie, LockInfo* lock, uint32 sequence, +RequestBuilder::Lock(OpenState* state, LockInfo* lock, uint32 sequence, bool reclaim) { if (fProcedure != ProcCompound) @@ -226,8 +227,6 @@ RequestBuilder::Lock(OpenFileCookie* cookie, LockInfo* lock, uint32 sequence, fRequest->Stream().AddBoolean(true); // new lock owner // open seq stateid - OpenState* state = cookie->fOpenState; - fRequest->Stream().AddUInt(sequence); fRequest->Stream().AddUInt(state->fStateSeq); fRequest->Stream().AddUInt(state->fStateID[0]); @@ -236,7 +235,7 @@ RequestBuilder::Lock(OpenFileCookie* cookie, LockInfo* lock, uint32 sequence, // lock seq owner fRequest->Stream().AddUInt(lock->fOwner->fSequence++); - _GenerateLockOwner(fRequest->Stream(), cookie, lock->fOwner); + _GenerateLockOwner(fRequest->Stream(), state, lock->fOwner); } else { fRequest->Stream().AddBoolean(false); // old lock owner @@ -258,7 +257,7 @@ RequestBuilder::Lock(OpenFileCookie* cookie, LockInfo* lock, uint32 sequence, status_t RequestBuilder::LockT(LockType type, uint64 pos, uint64 len, - OpenFileCookie* cookie) + OpenState* state) { if (fProcedure != ProcCompound) return B_BAD_VALUE; @@ -272,7 +271,7 @@ RequestBuilder::LockT(LockType type, uint64 pos, uint64 len, fRequest->Stream().AddUHyper(pos); fRequest->Stream().AddUHyper(len); - fRequest->Stream().AddUHyper(cookie->fOpenState->fClientID); + fRequest->Stream().AddUHyper(state->fClientID); uint32 owner = find_thread(NULL); fRequest->Stream().AddOpaque(&owner, sizeof(owner)); @@ -381,7 +380,7 @@ RequestBuilder::Nverify(AttrValue* attr, uint32 count) status_t RequestBuilder::Open(OpenClaim claim, uint32 seq, uint32 access, uint64 id, OpenCreate oc, uint64 ownerId, const char* name, AttrValue* attr, - uint32 count, bool excl) + uint32 count, bool excl, OpenDelegation delegationType) { if (fProcedure != ProcCompound) return B_BAD_VALUE; @@ -413,7 +412,7 @@ RequestBuilder::Open(OpenClaim claim, uint32 seq, uint32 access, uint64 id, fRequest->Stream().AddString(name, strlen(name)); break; case CLAIM_PREVIOUS: - fRequest->Stream().AddUInt(0); + fRequest->Stream().AddUInt(delegationType); break; default: return B_UNSUPPORTED; @@ -795,7 +794,7 @@ RequestBuilder::Write(const uint32* id, uint32 stateSeq, const void* buffer, status_t -RequestBuilder::ReleaseLockOwner(OpenFileCookie* cookie, LockOwner* owner) +RequestBuilder::ReleaseLockOwner(OpenState* state, LockOwner* owner) { if (fProcedure != ProcCompound) return B_BAD_VALUE; @@ -803,7 +802,7 @@ RequestBuilder::ReleaseLockOwner(OpenFileCookie* cookie, LockOwner* owner) return B_NO_MEMORY; fRequest->Stream().AddUInt(OpReleaseLockOwner); - _GenerateLockOwner(fRequest->Stream(), cookie, owner); + _GenerateLockOwner(fRequest->Stream(), state, owner); fOpCount++; diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h index d850c3c176..d958d6d05a 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h @@ -19,7 +19,7 @@ #include "XDR.h" -class OpenFileCookie; +class OpenState; class LockInfo; class LockOwner; @@ -41,11 +41,10 @@ public: status_t GetAttr(Attribute* attrs, uint32 count); status_t GetFH(); status_t Link(const char* name); - status_t Lock(OpenFileCookie* cookie, - LockInfo* lock, uint32 sequence, - bool reclaim = false); + status_t Lock(OpenState* state, LockInfo* lock, + uint32 sequence, bool reclaim = false); status_t LockT(LockType type, uint64 pos, - uint64 len, OpenFileCookie* cookie); + uint64 len, OpenState* state); status_t LockU(LockInfo* lock); status_t LookUp(const char* name); status_t LookUpUp(); @@ -54,7 +53,9 @@ public: uint32 access, uint64 id, OpenCreate oc, uint64 ownerId, const char* name, AttrValue* attr = NULL, - uint32 count = 0, bool excl = false); + uint32 count = 0, bool excl = false, + OpenDelegation delegType + = OPEN_DELEGATE_NONE); status_t OpenConfirm(uint32 seq, const uint32* id, uint32 stateSeq); status_t PutFH(const FileHandle& fh); @@ -77,7 +78,7 @@ public: status_t Write(const uint32* id, uint32 stateSeq, const void* buffer, uint64 pos, uint32 len); - status_t ReleaseLockOwner(OpenFileCookie* cookie, + status_t ReleaseLockOwner(OpenState* state, LockOwner* owner); RPC::Call* Request(); @@ -86,8 +87,7 @@ private: void _InitHeader(); void _GenerateLockOwner(XDR::WriteStream& stream, - OpenFileCookie* cookie, - LockOwner* owner); + OpenState* state, LockOwner* owner); status_t _GenerateClientId(XDR::WriteStream& stream, const RPC::Server* server); From e2e5f06d6e736c019ed37c475ff4f68e3c4f401c Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Mon, 6 Aug 2012 03:25:02 +0200 Subject: [PATCH 165/252] nfs4: Do not sync too often if delegation is held --- .../kernel/file_systems/nfs4/Delegation.cpp | 10 +++------- .../kernel/file_systems/nfs4/Delegation.h | 3 --- src/add-ons/kernel/file_systems/nfs4/Inode.cpp | 17 +++++++++++++---- src/add-ons/kernel/file_systems/nfs4/Inode.h | 1 + .../kernel/file_systems/nfs4/InodeRegular.cpp | 3 +-- .../file_systems/nfs4/kernel_interface.cpp | 6 +----- 6 files changed, 19 insertions(+), 21 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Delegation.cpp b/src/add-ons/kernel/file_systems/nfs4/Delegation.cpp index 299cf2143e..7d64adba61 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Delegation.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Delegation.cpp @@ -20,20 +20,16 @@ Delegation::Delegation(const OpenDelegationData& data, Inode* inode, fData(data), fInode(inode) { - rw_lock_init(&fLock, NULL); } -Delegation::~Delegation() -{ - rw_lock_destroy(&fLock); -} - status_t Delegation::GiveUp(bool truncate) { if (!truncate) { - // save buffers + fInode->SyncAndCommit(true); + + // TODO: claim locks } ReturnDelegation(); diff --git a/src/add-ons/kernel/file_systems/nfs4/Delegation.h b/src/add-ons/kernel/file_systems/nfs4/Delegation.h index 27099e2281..9d67afb371 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Delegation.h +++ b/src/add-ons/kernel/file_systems/nfs4/Delegation.h @@ -22,7 +22,6 @@ class Delegation : public NFS4Object, public: Delegation(const OpenDelegationData& data, Inode* inode, uint64 clientID); - ~Delegation(); // TODO: locks @@ -38,8 +37,6 @@ private: uint64 fClientID; OpenDelegationData fData; Inode* fInode; - - rw_lock fLock; }; diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index e56fdc9998..e2362da7fb 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -648,8 +648,7 @@ Inode::AcquireLock(OpenFileCookie* cookie, const struct flock* lock, status_t Inode::ReleaseLock(OpenFileCookie* cookie, const struct flock* lock) { - file_cache_sync(fFileCache); - Commit(); + SyncAndCommit(); LockInfo* prev = NULL; @@ -699,8 +698,7 @@ Inode::ReleaseLock(OpenFileCookie* cookie, const struct flock* lock) status_t Inode::ReleaseAllLocks(OpenFileCookie* cookie) { - file_cache_sync(fFileCache); - Commit(); + SyncAndCommit(); OpenState* state = cookie->fOpenState; MutexLocker _(state->fLocksLock); @@ -790,3 +788,14 @@ Inode::RecallDelegation(bool truncate) fDelegation = NULL; } + +status_t +Inode::SyncAndCommit(bool force) +{ + if (!force && fDelegation != NULL) + return B_OK; + + file_cache_sync(fFileCache); + return Commit(); +} + diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h b/src/add-ons/kernel/file_systems/nfs4/Inode.h index 4c56e75289..e5d90c267e 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -42,6 +42,7 @@ public: status_t Access(int mode); status_t Commit(); + status_t SyncAndCommit(bool force = false); status_t CreateObject(const char* name, const char* path, int mode, FileType type); diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp index 76e4820af7..0056512c9e 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp @@ -146,8 +146,7 @@ Inode::Open(int mode, OpenFileCookie* cookie) status_t Inode::Close(OpenFileCookie* cookie) { - file_cache_sync(fFileCache); - Commit(); + SyncAndCommit(); MutexLocker _(fStateLock); if (cookie->fOpenState != NULL) { 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 4804c6cce7..6da6cd15f1 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -308,11 +308,7 @@ static status_t nfs4_fsync(fs_volume* volume, fs_vnode* vnode) { Inode* inode = reinterpret_cast(vnode->private_node); - status_t result = file_cache_sync(inode->FileCache()); - if (result != B_OK) - return result; - - return inode->Commit(); + return inode->SyncAndCommit(); } From 2c36184f198a0511e54da85e20b5bf1379503660 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Mon, 6 Aug 2012 16:41:34 +0200 Subject: [PATCH 166/252] nfs4: Support delegations of created files --- src/add-ons/kernel/file_systems/nfs4/Inode.h | 6 ++++-- .../kernel/file_systems/nfs4/InodeRegular.cpp | 11 +++++++---- .../kernel/file_systems/nfs4/NFS4Inode.cpp | 9 ++++----- src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h | 3 ++- .../file_systems/nfs4/kernel_interface.cpp | 16 +++++++++++++++- 5 files changed, 32 insertions(+), 13 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h b/src/add-ons/kernel/file_systems/nfs4/Inode.h index e5d90c267e..68928bf941 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -59,7 +59,8 @@ public: status_t WriteStat(const struct stat* st, uint32 mask); status_t Create(const char* name, int mode, int perms, - OpenFileCookie* cookie, ino_t* id); + OpenFileCookie* cookie, + OpenDelegationData* data, ino_t* id); status_t Open(int mode, OpenFileCookie* cookie); status_t Close(OpenFileCookie* cookie); status_t Read(OpenFileCookie* cookie, off_t pos, @@ -89,7 +90,8 @@ protected: Inode(); status_t CreateState(const char* name, int mode, - int perms, OpenState* state); + int perms, OpenState* state, + OpenDelegationData* data); status_t ReadDirUp(struct dirent* de, uint32 pos, uint32 size); diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp index 0056512c9e..452648779a 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp @@ -20,13 +20,14 @@ status_t -Inode::CreateState(const char* name, int mode, int perms, OpenState* state) { +Inode::CreateState(const char* name, int mode, int perms, OpenState* state, + OpenDelegationData* delegationData) { uint64 fileID; FileHandle handle; ChangeInfo changeInfo; status_t result = CreateFile(name, mode, perms, state, &changeInfo, - &fileID, &handle); + &fileID, &handle, delegationData); if (result != B_OK) return result; @@ -64,7 +65,7 @@ Inode::CreateState(const char* name, int mode, int perms, OpenState* state) { status_t Inode::Create(const char* name, int mode, int perms, OpenFileCookie* cookie, - ino_t* id) + OpenDelegationData* data, ino_t* id) { cookie->fMode = mode; cookie->fLocks = NULL; @@ -72,7 +73,7 @@ Inode::Create(const char* name, int mode, int perms, OpenFileCookie* cookie, MutexLocker _(fStateLock); OpenState* state = new OpenState; - status_t result = CreateState(name, mode, perms, state); + status_t result = CreateState(name, mode, perms, state, data); if (result != B_OK) return result; @@ -99,6 +100,8 @@ Inode::Open(int mode, OpenFileCookie* cookie) OpenDelegationData data; data.fType = OPEN_DELEGATE_NONE; if (fOpenState == NULL) { + // TODO: revalidate cache + OpenState* state = new OpenState; if (state == NULL) return B_NO_MEMORY; diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp index e45f08f4f2..67649d998a 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp @@ -381,15 +381,14 @@ NFS4Inode::Rename(Inode* from, Inode* to, const char* fromName, status_t -NFS4Inode::CreateFile(const char* name, int mode, int perms, - OpenState* state, ChangeInfo* changeInfo, uint64* fileID, - FileHandle* handle) +NFS4Inode::CreateFile(const char* name, int mode, int perms, OpenState* state, + ChangeInfo* changeInfo, uint64* fileID, FileHandle* handle, + OpenDelegationData* delegation) { bool confirm; status_t result; bool badOwner = false; - OpenDelegationData delegation; uint32 sequence = fFileSystem->OpenOwnerSequenceLock(); do { state->fClientID = fFileSystem->NFSServer()->ClientId(); @@ -461,7 +460,7 @@ NFS4Inode::CreateFile(const char* name, int mode, int perms, reply.PutFH(); result = reply.Open(state->fStateID, &state->fStateSeq, &confirm, - &delegation, changeInfo); + delegation, changeInfo); if (result != B_OK) return result; diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h index 968e6705b5..3e1bedb429 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h @@ -46,7 +46,8 @@ protected: status_t CreateFile(const char* name, int mode, int perms, OpenState* state, ChangeInfo* changeInfo, - uint64* fileID, FileHandle* handle); + uint64* fileID, FileHandle* handle, + OpenDelegationData* delegation); status_t OpenFile(OpenState* state, int mode, OpenDelegationData* delegation); 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 6da6cd15f1..9a9f8b9c23 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -392,7 +392,10 @@ nfs4_create(fs_volume* volume, fs_vnode* dir, const char* name, int openMode, *_cookie = cookie; Inode* inode = reinterpret_cast(dir->private_node); - status_t result = inode->Create(name, openMode, perms, cookie, _newVnodeID); + + OpenDelegationData data; + status_t result = inode->Create(name, openMode, perms, cookie, &data, + _newVnodeID); if (result != B_OK) { delete cookie; return result; @@ -417,6 +420,17 @@ nfs4_create(fs_volume* volume, fs_vnode* dir, const char* name, int openMode, child->SetOpenState(cookie->fOpenState); + if (data.fType != OPEN_DELEGATE_NONE) { + Delegation* delegation + = new(std::nothrow) Delegation(data, child, + cookie->fOpenState->fClientID); + if (delegation != NULL) { + delegation->fInfo = cookie->fOpenState->fInfo; + delegation->fFileSystem = child->GetFileSystem(); + child->SetDelegation(delegation); + } + } + return result; } From cde3994e6907eaa3324ce4918b259b65da290c84 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Mon, 6 Aug 2012 18:14:55 +0200 Subject: [PATCH 167/252] nfs4: Return delegation before open upgrade --- .../kernel/file_systems/nfs4/Delegation.cpp | 5 +--- .../kernel/file_systems/nfs4/Delegation.h | 2 -- .../kernel/file_systems/nfs4/Inode.cpp | 30 +++++++++++++++++-- src/add-ons/kernel/file_systems/nfs4/Inode.h | 3 ++ .../kernel/file_systems/nfs4/InodeRegular.cpp | 20 ++++++++++--- .../file_systems/nfs4/MetadataCache.cpp | 28 +++++++++++++++-- .../kernel/file_systems/nfs4/MetadataCache.h | 4 +++ .../kernel/file_systems/nfs4/NFS4Server.cpp | 1 + 8 files changed, 79 insertions(+), 14 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Delegation.cpp b/src/add-ons/kernel/file_systems/nfs4/Delegation.cpp index 7d64adba61..80aeb4330a 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Delegation.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Delegation.cpp @@ -26,12 +26,9 @@ Delegation::Delegation(const OpenDelegationData& data, Inode* inode, status_t Delegation::GiveUp(bool truncate) { - if (!truncate) { + if (!truncate) fInode->SyncAndCommit(true); - // TODO: claim locks - } - ReturnDelegation(); return B_OK; diff --git a/src/add-ons/kernel/file_systems/nfs4/Delegation.h b/src/add-ons/kernel/file_systems/nfs4/Delegation.h index 9d67afb371..19afcfb450 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Delegation.h +++ b/src/add-ons/kernel/file_systems/nfs4/Delegation.h @@ -23,8 +23,6 @@ public: Delegation(const OpenDelegationData& data, Inode* inode, uint64 clientID); - // TODO: locks - status_t GiveUp(bool truncate = false); inline Inode* GetInode(); diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index e2362da7fb..1121a6e765 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -139,6 +139,9 @@ Inode::~Inode() status_t Inode::RevalidateFileCache() { + if (fDelegation != NULL) + return B_OK; + uint64 change; status_t result = GetChangeInfo(&change); if (result != B_OK) @@ -153,8 +156,7 @@ Inode::RevalidateFileCache() if (result != B_OK) return result; - file_cache_sync(fFileCache); - Commit(); + SyncAndCommit(true); file_cache_delete(fFileCache); fFileCache = file_cache_create(fFileSystem->DevId(), ID(), st.st_size); @@ -760,6 +762,12 @@ void Inode::SetDelegation(Delegation* delegation) { WriteLocker _(fDelegationLock); + + fMetaCache.InvalidateStat(); + struct stat st; + Stat(&st); + fMetaCache.LockValid(); + fDelegation = delegation; fOpenState->AcquireReference(); fOpenState->fDelegation = delegation; @@ -773,6 +781,24 @@ Inode::RecallDelegation(bool truncate) WriteLocker _(fDelegationLock); if (fDelegation == NULL) return; + ReturnDelegation(truncate); +} + + +void +Inode::RecallReadDelegation() +{ + WriteLocker _(fDelegationLock); + if (fDelegation == NULL || fDelegation->Type() != OPEN_DELEGATE_READ) + return; + ReturnDelegation(false); +} + + +void +Inode::ReturnDelegation(bool truncate) +{ + fMetaCache.UnlockValid(); fDelegation->GiveUp(truncate); fFileSystem->RemoveDelegation(fDelegation); diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h b/src/add-ons/kernel/file_systems/nfs4/Inode.h index 68928bf941..d2bafcf5db 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -36,6 +36,7 @@ public: void SetDelegation(Delegation* delegation); void RecallDelegation(bool truncate = false); + void RecallReadDelegation(); status_t LookUp(const char* name, ino_t* id); @@ -93,6 +94,8 @@ protected: int perms, OpenState* state, OpenDelegationData* data); + void ReturnDelegation(bool truncate); + status_t ReadDirUp(struct dirent* de, uint32 pos, uint32 size); status_t FillDirEntry(struct dirent* de, ino_t id, diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp index 452648779a..cc53d1d070 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp @@ -95,12 +95,12 @@ Inode::Create(const char* name, int mode, int perms, OpenFileCookie* cookie, status_t Inode::Open(int mode, OpenFileCookie* cookie) { - MutexLocker _(fStateLock); + MutexLocker locker(fStateLock); OpenDelegationData data; data.fType = OPEN_DELEGATE_NONE; if (fOpenState == NULL) { - // TODO: revalidate cache + RevalidateFileCache(); OpenState* state = new OpenState; if (state == NULL) @@ -114,16 +114,28 @@ Inode::Open(int mode, OpenFileCookie* cookie) fFileSystem->AddOpenFile(state); fOpenState = state; + locker.Unlock(); } else { + fOpenState->AcquireReference(); + locker.Unlock(); + int newMode = mode & O_RWMASK; int oldMode = fOpenState->fMode & O_RWMASK; if (oldMode != newMode && oldMode != O_RDWR) { + if (oldMode == O_RDONLY) + RecallReadDelegation(); + status_t result = OpenFile(fOpenState, O_RDWR, &data); - if (result != B_OK) + if (result != B_OK) { + locker.Lock(); + if (fOpenState->ReleaseReference() == 1) { + fFileSystem->RemoveOpenFile(fOpenState); + fOpenState = NULL; + } return result; + } fOpenState->fMode = O_RDWR; } - fOpenState->AcquireReference(); } cookie->fOpenState = fOpenState; diff --git a/src/add-ons/kernel/file_systems/nfs4/MetadataCache.cpp b/src/add-ons/kernel/file_systems/nfs4/MetadataCache.cpp index d8ba4bec3d..058ce243c2 100644 --- a/src/add-ons/kernel/file_systems/nfs4/MetadataCache.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/MetadataCache.cpp @@ -12,7 +12,8 @@ MetadataCache::MetadataCache() : - fExpire(0) + fExpire(0), + fForceValid(false) { mutex_init(&fLock, NULL); } @@ -28,7 +29,7 @@ status_t MetadataCache::GetStat(struct stat* st) { MutexLocker _(fLock); - if (fExpire > time(NULL)) { + if (fForceValid || fExpire > time(NULL)) { // Do not touch other members of struct stat st->st_size = fStatCache.st_size; st->st_mode = fStatCache.st_mode; @@ -97,3 +98,26 @@ MetadataCache::SetAccess(uid_t uid, uint32 allowed) fAccessCache.Insert(uid, entry); } + +status_t +MetadataCache::LockValid() +{ + MutexLocker _(fLock); + if (fForceValid || fExpire > time(NULL)) { + fForceValid = true; + return B_OK; + } + + return B_ERROR; +} + + +void +MetadataCache::UnlockValid() +{ + MutexLocker _(fLock); + fExpire = time(NULL) + kExpirationTime; + fForceValid = false; +} + + diff --git a/src/add-ons/kernel/file_systems/nfs4/MetadataCache.h b/src/add-ons/kernel/file_systems/nfs4/MetadataCache.h index ecf12e70e2..4622c9e7dd 100644 --- a/src/add-ons/kernel/file_systems/nfs4/MetadataCache.h +++ b/src/add-ons/kernel/file_systems/nfs4/MetadataCache.h @@ -32,6 +32,9 @@ public: status_t GetAccess(uid_t uid, uint32* allowed); void SetAccess(uid_t uid, uint32 allowed); + status_t LockValid(); + void UnlockValid(); + inline void InvalidateStat(); inline void InvalidateAccess(); @@ -41,6 +44,7 @@ public: private: struct stat fStatCache; time_t fExpire; + bool fForceValid; AVLTreeMap fAccessCache; diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp index 05c85035f5..274ac6a3ce 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp @@ -332,6 +332,7 @@ NFS4Server::CallbackRecall(RequestInterpreter* request, ReplyBuilder* reply) delegation->GetInode()->RecallDelegation(truncate); reply->Recall(B_OK); + return B_OK; } From f1fe25e50864bd85cf8443b891d29dfa190b8c32 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Mon, 6 Aug 2012 18:30:02 +0200 Subject: [PATCH 168/252] nfs4: Repair O_TRUNC support --- src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp | 7 +++++++ src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp | 9 --------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp index cc53d1d070..f132762264 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp @@ -138,6 +138,13 @@ Inode::Open(int mode, OpenFileCookie* cookie) } } + if ((mode & O_TRUNC) == O_TRUNC) { + struct stat st; + st.st_size = 0; + WriteStat(&st, B_STAT_SIZE); + file_cache_set_size(fFileCache, 0); + } + cookie->fOpenState = fOpenState; cookie->fFileSystem = fFileSystem; diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp index 67649d998a..a424350b29 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp @@ -526,15 +526,6 @@ NFS4Inode::OpenFile(OpenState* state, int mode, OpenDelegationData* delegation) } 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, sequence, sModeToAccess(mode), - state->fClientID, OPEN4_CREATE, fFileSystem->OpenOwner(), - fInfo.fName, &attr, 1, false); - } else req.Open(CLAIM_NULL, sequence, sModeToAccess(mode), state->fClientID, OPEN4_NOCREATE, fFileSystem->OpenOwner(), fInfo.fName); req.GetFH(); From 412174162e796c3208a93041f33b7de45425c847 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Mon, 6 Aug 2012 22:41:20 +0200 Subject: [PATCH 169/252] nfs4: Add asynchronous work queue --- .../kernel/file_systems/nfs4/Connection.cpp | 2 +- src/add-ons/kernel/file_systems/nfs4/Jamfile | 1 + .../kernel/file_systems/nfs4/NFS4Server.cpp | 37 +++- .../kernel/file_systems/nfs4/NFS4Server.h | 1 + .../file_systems/nfs4/RPCCallbackServer.cpp | 4 +- .../kernel/file_systems/nfs4/WorkQueue.cpp | 184 ++++++++++++++++++ .../kernel/file_systems/nfs4/WorkQueue.h | 82 ++++++++ .../file_systems/nfs4/kernel_interface.cpp | 30 ++- 8 files changed, 333 insertions(+), 8 deletions(-) create mode 100644 src/add-ons/kernel/file_systems/nfs4/WorkQueue.cpp create mode 100644 src/add-ons/kernel/file_systems/nfs4/WorkQueue.h diff --git a/src/add-ons/kernel/file_systems/nfs4/Connection.cpp b/src/add-ons/kernel/file_systems/nfs4/Connection.cpp index cc4611b9d8..322ef47a7c 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Connection.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Connection.cpp @@ -163,7 +163,7 @@ ServerAddress::InAddr() const status_t ServerAddress::ResolveName(const char* name, ServerAddress* address) { - address->fProtocol = IPPROTO_TCP; + address->fProtocol = IPPROTO_UDP; // getaddrinfo() is very expensive when called from kernel, so we do not // want to call it unless there is no other choice. diff --git a/src/add-ons/kernel/file_systems/nfs4/Jamfile b/src/add-ons/kernel/file_systems/nfs4/Jamfile index a3a41946f2..246ba99d2a 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Jamfile +++ b/src/add-ons/kernel/file_systems/nfs4/Jamfile @@ -35,6 +35,7 @@ KernelAddon nfs4 : RPCCallbackServer.cpp RPCReply.cpp RPCServer.cpp + WorkQueue.cpp XDR.cpp ; diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp index 274ac6a3ce..9ea450b910 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp @@ -11,6 +11,7 @@ #include "Inode.h" #include "NFS4Server.h" #include "Request.h" +#include "WorkQueue.h" NFS4Server::NFS4Server(RPC::Server* serv) @@ -247,6 +248,9 @@ NFS4Server::_Renewal() request.Send(); switch (request.Reply().NFS4Error()) { + case NFS4ERR_CB_PATH_DOWN: + RecallAll(); + break; case NFS4ERR_STALE_CLIENTID: ServerRebooted(clientId); break; @@ -328,11 +332,40 @@ NFS4Server::CallbackRecall(RequestInterpreter* request, ReplyBuilder* reply) return B_FILE_NOT_FOUND; } - // TODO: should be asynchronous - delegation->GetInode()->RecallDelegation(truncate); + DelegationRecallArgs* args = new(std::nothrow) DelegationRecallArgs; + args->fDelegation = delegation; + args->fTruncate = truncate; + gWorkQueue->EnqueueJob(DelegationRecall, args); reply->Recall(B_OK); return B_OK; } + +status_t +NFS4Server::RecallAll() +{ +#if 0 + MutexLocker locker(fFSLock); + + Delegation* delegation = NULL; + FileSystem* current = fFileSystems; + while (current != NULL) { + delegation = current->GetDelegation(handle); + if (delegation != NULL) + break; + + current = current->fNext; + } + locker.Unlock(); + + DelegationRecallArgs args = new(std::nothrow) DelegationRecallArgs; + DelegationRecallArgs* args; + args->fDelegation = delegation; + args->fTruncate = truncate; + gWorkQueue->EnqueueJob(DelegationRecall, args); +#endif + return B_OK; +} + diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h index d312018e21..fe159b3b74 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h @@ -42,6 +42,7 @@ public: status_t CallbackRecall(RequestInterpreter* request, ReplyBuilder* reply); + status_t RecallAll(); private: status_t _GetLeaseTime(); diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCCallbackServer.cpp b/src/add-ons/kernel/file_systems/nfs4/RPCCallbackServer.cpp index b007a3ba99..54fd3d346f 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RPCCallbackServer.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RPCCallbackServer.cpp @@ -26,7 +26,7 @@ CallbackServer::CallbackServer() fConnectionList(NULL), fListener(NULL), fThreadRunning(false), - //fCallbackArray(NULL), + fCallbackArray(NULL), fArraySize(0), fFreeSlot(-1) { @@ -40,7 +40,7 @@ CallbackServer::~CallbackServer() { StopServer(); - //free(fCallbackArray); + free(fCallbackArray); rw_lock_destroy(&fArrayLock); mutex_destroy(&fThreadLock); mutex_destroy(&fConnectionLock); diff --git a/src/add-ons/kernel/file_systems/nfs4/WorkQueue.cpp b/src/add-ons/kernel/file_systems/nfs4/WorkQueue.cpp new file mode 100644 index 0000000000..9d387248cf --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/WorkQueue.cpp @@ -0,0 +1,184 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ + + +#include "WorkQueue.h" + +#include + + +WorkQueue* gWorkQueue = NULL; + + +WorkQueue::WorkQueue() + : + fQueueSemaphore(create_sem(0, NULL)), + fThreadCancel(create_sem(0, NULL)) +{ + mutex_init(&fQueueLock, NULL); + + fThread = spawn_kernel_thread(&WorkQueue::LaunchWorkingThread, + "NFSv4 Work Queue", B_NORMAL_PRIORITY, this); + if (fThread < B_OK) { + fInitError = fThread; + return; + } + + status_t result = resume_thread(fThread); + if (result != B_OK) { + kill_thread(fThread); + fInitError = result; + return; + } + + fInitError = B_OK; +} + + +WorkQueue::~WorkQueue() +{ + release_sem(fThreadCancel); + + status_t result; + wait_for_thread(fThread, &result); + + mutex_destroy(&fQueueLock); + delete_sem(fThreadCancel); + delete_sem(fQueueSemaphore); +} + + +status_t +WorkQueue::EnqueueJob(JobType type, void* args) +{ + WorkQueueEntry* entry = new(std::nothrow) WorkQueueEntry; + if (entry == NULL) + return B_NO_MEMORY; + + entry->fType = type; + entry->fArguments = args; + MutexLocker locker(fQueueLock); + fQueue.InsertAfter(fQueue.Tail(), entry); + locker.Unlock(); + + release_sem(fQueueSemaphore); + return B_OK; +} + + +status_t +WorkQueue::LaunchWorkingThread(void* object) +{ + WorkQueue* queue = reinterpret_cast(object); + return queue->WorkingThread(); +} + + +status_t +WorkQueue::WorkingThread() +{ + while (true) { + object_wait_info object[2]; + object[0].object = fThreadCancel; + object[0].type = B_OBJECT_TYPE_SEMAPHORE; + object[0].events = B_EVENT_ACQUIRE_SEMAPHORE; + + object[1].object = fQueueSemaphore; + object[1].type = B_OBJECT_TYPE_SEMAPHORE; + object[1].events = B_EVENT_ACQUIRE_SEMAPHORE; + + status_t result = wait_for_objects(object, 2); + + if (result < B_OK || + (object[0].events & B_EVENT_ACQUIRE_SEMAPHORE) != 0) { + return result; + } else if ((object[1].events & B_EVENT_ACQUIRE_SEMAPHORE) == 0) + continue; + + acquire_sem(fQueueSemaphore); + + DequeueJob(); + } + + return B_OK; +} + + +void +WorkQueue::DequeueJob() +{ + MutexLocker locker(fQueueLock); + + WorkQueueEntry* entry = fQueue.RemoveHead(); + + void* args = entry->fArguments; + switch (entry->fType) { + case DelegationRecall: + JobRecall(reinterpret_cast(args)); + break; + case IORequest: + JobIO(reinterpret_cast(args)); + break; + } + + delete entry; +} + + +void +WorkQueue::JobRecall(DelegationRecallArgs* args) +{ + args->fDelegation->GetInode()->RecallDelegation(args->fTruncate); +} + + +void +WorkQueue::JobIO(IORequestArgs* args) +{ + uint64 offset = io_request_offset(args->fRequest); + uint64 length = io_request_length(args->fRequest); + + char* buffer = reinterpret_cast(malloc(length)); + if (buffer == NULL) { + notify_io_request(args->fRequest, B_NO_MEMORY); + return; + } + + bool eof = false; + uint64 size = 0; + status_t result; + if (io_request_is_write(args->fRequest)) { + result = read_from_io_request(args->fRequest, buffer, length); + + do { + size_t bytesWritten = length - size; + result = args->fInode->WriteDirect(NULL, offset + size, + buffer + size, &bytesWritten); + size += bytesWritten; + } while (size < length && result == B_OK); + } else { + do { + size_t bytesRead = length - size; + result = args->fInode->ReadDirect(NULL, offset + size, buffer, + &bytesRead, &eof); + if (result != B_OK) + break; + + result = write_to_io_request(args->fRequest, buffer, bytesRead); + if (result != B_OK) + break; + + size += bytesRead; + } while (size < length && result == B_OK && !eof); + + } + free(buffer); + + notify_io_request(args->fRequest, result); +} + diff --git a/src/add-ons/kernel/file_systems/nfs4/WorkQueue.h b/src/add-ons/kernel/file_systems/nfs4/WorkQueue.h new file mode 100644 index 0000000000..954d011388 --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/WorkQueue.h @@ -0,0 +1,82 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ +#ifndef WORKQUEUE_H +#define WORKQUEUE_H + + +#include +#include +#include +#include + +#include "Delegation.h" +#include "Inode.h" + + +enum JobType { + DelegationRecall, + IORequest +}; + +struct DelegationRecallArgs { + Delegation* fDelegation; + bool fTruncate; +}; + +struct IORequestArgs { + io_request* fRequest; + Inode* fInode; +}; + +struct WorkQueueEntry : public DoublyLinkedListLinkImpl { + JobType fType; + void* fArguments; +}; + +class WorkQueue { +public: + WorkQueue(); + ~WorkQueue(); + + inline status_t InitStatus(); + + status_t EnqueueJob(JobType type, void* args); + +protected: + static status_t LaunchWorkingThread(void* object); + status_t WorkingThread(); + + void DequeueJob(); + + void JobRecall(DelegationRecallArgs* args); + void JobIO(IORequestArgs* args); + +private: + status_t fInitError; + + sem_id fQueueSemaphore; + mutex fQueueLock; + DoublyLinkedList fQueue; + + sem_id fThreadCancel; + thread_id fThread; +}; + + +inline status_t +WorkQueue::InitStatus() +{ + return fInitError; +} + + +extern WorkQueue* gWorkQueue; + + +#endif // WORKQUEUE_H + 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 9a9f8b9c23..f396be2df2 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -22,6 +22,7 @@ #include "RootInode.h" #include "RPCCallbackServer.h" #include "RPCServer.h" +#include "WorkQueue.h" extern fs_volume_ops gNFSv4VolumeOps; @@ -282,8 +283,21 @@ nfs4_write_pages(fs_volume* _volume, fs_vnode* vnode, void* _cookie, off_t pos, static status_t nfs4_io(fs_volume* volume, fs_vnode* vnode, void* cookie, io_request* request) { - // no asynchronous calls yet - return B_UNSUPPORTED; + Inode* inode = reinterpret_cast(vnode->private_node); + + IORequestArgs* args = new(std::nothrow) IORequestArgs; + if (args == NULL) { + notify_io_request(request, B_NO_MEMORY); + return B_NO_MEMORY; + } + args->fRequest = request; + args->fInode = inode; + + status_t result = gWorkQueue->EnqueueJob(IORequest, args); + if (result != B_OK) + notify_io_request(request, result); + + return result; } @@ -651,10 +665,19 @@ nfs4_init() return B_NO_MEMORY; } + gWorkQueue = new(std::nothrow) WorkQueue; + if (gWorkQueue == NULL || gWorkQueue->InitStatus() != B_OK) { + delete gWorkQueue; + delete gIdMapper; + delete gRPCServerManager; + return B_NO_MEMORY; + } + gRPCCallbackServer = new(std::nothrow) RPC::CallbackServer; if (gRPCCallbackServer == NULL) { - delete gRPCServerManager; delete gIdMapper; + delete gWorkQueue; + delete gRPCServerManager; return B_NO_MEMORY; } @@ -669,6 +692,7 @@ nfs4_uninit() delete gRPCCallbackServer; delete gIdMapper; + delete gWorkQueue; delete gRPCServerManager; return B_OK; From 0dff48c7ea15e3ee52598682f5da108558987c20 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Mon, 6 Aug 2012 22:52:35 +0200 Subject: [PATCH 170/252] nfs4: Recall all delegations when callback path is down --- .../kernel/file_systems/nfs4/FileSystem.cpp | 18 +++++++++++ .../kernel/file_systems/nfs4/FileSystem.h | 3 ++ .../kernel/file_systems/nfs4/NFS4Server.cpp | 32 +++++++++---------- 3 files changed, 37 insertions(+), 16 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp b/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp index 9379f3e638..ecc56b28db 100644 --- a/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp @@ -311,11 +311,28 @@ FileSystem::RemoveOpenFile(OpenState* state) } +DoublyLinkedList& +FileSystem::DelegationsLock() +{ + mutex_lock(&fDelegationLock); + return fDelegationList; +} + + +void +FileSystem::DelegationsUnlock() +{ + mutex_unlock(&fDelegationLock); +} + + void FileSystem::AddDelegation(Delegation* delegation) { MutexLocker _(fDelegationLock); + fDelegationList.InsertBefore(fDelegationList.Head(), delegation); + fHandleToDelegation.Remove(delegation->fInfo.fHandle); fHandleToDelegation.Insert(delegation->fInfo.fHandle, delegation); @@ -328,6 +345,7 @@ FileSystem::RemoveDelegation(Delegation* delegation) { MutexLocker _(fDelegationLock); + fDelegationList.Remove(delegation); fHandleToDelegation.Remove(delegation->fInfo.fHandle); NFSServer()->DecUsage(); diff --git a/src/add-ons/kernel/file_systems/nfs4/FileSystem.h b/src/add-ons/kernel/file_systems/nfs4/FileSystem.h index 0bd634dd6e..adfea0a294 100644 --- a/src/add-ons/kernel/file_systems/nfs4/FileSystem.h +++ b/src/add-ons/kernel/file_systems/nfs4/FileSystem.h @@ -36,6 +36,8 @@ public: void AddOpenFile(OpenState* state); void RemoveOpenFile(OpenState* state); + DoublyLinkedList& DelegationsLock(); + void DelegationsUnlock(); void AddDelegation(Delegation* delegation); void RemoveDelegation(Delegation* delegation); Delegation* GetDelegation(const FileHandle& handle); @@ -68,6 +70,7 @@ private: CacheRevalidator fCacheRevalidator; mutex fDelegationLock; + DoublyLinkedList fDelegationList; AVLTreeMap fHandleToDelegation; OpenState* fOpenFiles; diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp index 9ea450b910..9dea65cc9a 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp @@ -346,26 +346,26 @@ NFS4Server::CallbackRecall(RequestInterpreter* request, ReplyBuilder* reply) status_t NFS4Server::RecallAll() { -#if 0 - MutexLocker locker(fFSLock); + MutexLocker _(fFSLock); + FileSystem* fs = fFileSystems; + while (fs != NULL) { + DoublyLinkedList& list = fs->DelegationsLock(); + DoublyLinkedList::Iterator iterator = list.GetIterator(); - Delegation* delegation = NULL; - FileSystem* current = fFileSystems; - while (current != NULL) { - delegation = current->GetDelegation(handle); - if (delegation != NULL) - break; + Delegation* current = iterator.Next(); + while (current != NULL) { + DelegationRecallArgs* args = new(std::nothrow) DelegationRecallArgs; + args->fDelegation = current; + args->fTruncate = false; + gWorkQueue->EnqueueJob(DelegationRecall, args); - current = current->fNext; + current = iterator.Next(); + } + fs->DelegationsUnlock(); + + fs = fs->fNext; } - locker.Unlock(); - DelegationRecallArgs args = new(std::nothrow) DelegationRecallArgs; - DelegationRecallArgs* args; - args->fDelegation = delegation; - args->fTruncate = truncate; - gWorkQueue->EnqueueJob(DelegationRecall, args); -#endif return B_OK; } From 224d602294491975618b856227b84120a5e1e0fc Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Mon, 6 Aug 2012 23:26:37 +0200 Subject: [PATCH 171/252] nfs4: Add support for CB_GETATTR --- src/add-ons/kernel/file_systems/nfs4/Inode.h | 17 +++++++ .../kernel/file_systems/nfs4/InodeRegular.cpp | 2 + .../kernel/file_systems/nfs4/NFS4Defs.h | 5 +++ .../kernel/file_systems/nfs4/NFS4Server.cpp | 45 +++++++++++++++++++ .../kernel/file_systems/nfs4/NFS4Server.h | 3 ++ .../kernel/file_systems/nfs4/ReplyBuilder.cpp | 34 ++++++++++++++ .../kernel/file_systems/nfs4/ReplyBuilder.h | 2 + .../file_systems/nfs4/RequestInterpreter.cpp | 34 ++++++++++++++ .../file_systems/nfs4/RequestInterpreter.h | 1 + 9 files changed, 143 insertions(+) diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h b/src/add-ons/kernel/file_systems/nfs4/Inode.h index d2bafcf5db..6dce7ba4cf 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -34,6 +34,9 @@ public: inline uint64 MaxFileSize(); + inline uint64 Change(); + inline bool Dirty(); + void SetDelegation(Delegation* delegation); void RecallDelegation(bool truncate = false); void RecallReadDelegation(); @@ -195,5 +198,19 @@ Inode::MaxFileSize() } +inline uint64 +Inode::Change() +{ + return fChange; +} + + +inline bool +Inode::Dirty() +{ + return fWriteDirty; +} + + #endif // INODE_H diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp index f132762264..a4dcd76d96 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp @@ -31,6 +31,8 @@ Inode::CreateState(const char* name, int mode, int perms, OpenState* state, if (result != B_OK) return result; + RevalidateFileCache(); + FileInfo fi; fi.fFileId = fileID; fi.fHandle = handle; diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h index c162462178..e60b45cd1e 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h @@ -26,6 +26,7 @@ enum CallbackProcedure { }; enum CallbackOpcode { + OpCallbackGetAttr = 3, OpCallbackRecall = 4 }; @@ -135,6 +136,10 @@ enum Attribute { FATTR4_MAXIMUM_ATTR_ID }; +enum CallbackAttr { + CallbackAttrSize = 1, + CallbackAttrChange = 2 +}; static inline bool sIsAttrSet(Attribute attr, const uint32* bitmap, uint32 count) diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp index 9dea65cc9a..07acb75e53 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp @@ -284,6 +284,9 @@ NFS4Server::ProcessCallback(RPC::CallbackRequest* request, for (uint32 i = 0; i < count; i++) { switch (req.Operation()) { + case OpCallbackGetAttr: + result = CallbackGetAttr(&req, &reply); + break; case OpCallbackRecall: result = CallbackRecall(&req, &reply); break; @@ -343,6 +346,48 @@ NFS4Server::CallbackRecall(RequestInterpreter* request, ReplyBuilder* reply) } +status_t +NFS4Server::CallbackGetAttr(RequestInterpreter* request, ReplyBuilder* reply) +{ + FileHandle handle; + int mask; + + status_t result = request->GetAttr(&handle, &mask); + if (result != B_OK) + return result; + return B_OK; + + MutexLocker locker(fFSLock); + + Delegation* delegation = NULL; + FileSystem* current = fFileSystems; + while (current != NULL) { + delegation = current->GetDelegation(handle); + if (delegation != NULL) + break; + + current = current->fNext; + } + locker.Unlock(); + + if (delegation == NULL) { + reply->GetAttr(B_FILE_NOT_FOUND, 0, 0, 0); + return B_FILE_NOT_FOUND; + } + + struct stat st; + delegation->GetInode()->Stat(&st); + + uint64 change; + change = delegation->GetInode()->Change(); + if (delegation->GetInode()->Dirty()) + change++; + reply->GetAttr(B_OK, mask, st.st_size, change); + + return B_OK; +} + + status_t NFS4Server::RecallAll() { diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h index fe159b3b74..4fe2dccb23 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h @@ -43,6 +43,9 @@ public: status_t CallbackRecall(RequestInterpreter* request, ReplyBuilder* reply); status_t RecallAll(); + + status_t CallbackGetAttr(RequestInterpreter* request, + ReplyBuilder* reply); private: status_t _GetLeaseTime(); diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyBuilder.cpp b/src/add-ons/kernel/file_systems/nfs4/ReplyBuilder.cpp index e18a4a64ad..152d5de25b 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyBuilder.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyBuilder.cpp @@ -56,6 +56,40 @@ ReplyBuilder::Reply() } +status_t +ReplyBuilder::GetAttr(status_t status, int mask, uint64 size, uint64 change) +{ + if (fStatus != B_OK) + return B_ERROR; + + fReply->Stream().AddUInt(OpCallbackGetAttr); + fReply->Stream().AddUInt(_HaikuErrorToNFS4(fStatus)); + fStatus = status; + + if (status == B_OK) { + uint32 bitmap = 0; + if ((mask & CallbackAttrChange) != 0) + bitmap |= 1 << FATTR4_CHANGE; + if ((mask & CallbackAttrSize) != 0) + bitmap |= 1 << FATTR4_SIZE; + fReply->Stream().AddUInt(1); + fReply->Stream().AddUInt(bitmap); + + XDR::WriteStream str; + if ((mask & CallbackAttrChange) != 0) + str.AddUHyper(change); + + if ((mask & CallbackAttrSize) != 0) + str.AddUHyper(size); + fReply->Stream().AddOpaque(str); + } + + fOpCount++; + + return B_OK; +} + + status_t ReplyBuilder::Recall(status_t status) { diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyBuilder.h b/src/add-ons/kernel/file_systems/nfs4/ReplyBuilder.h index be85416261..2a12a0d522 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyBuilder.h +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyBuilder.h @@ -22,6 +22,8 @@ public: RPC::CallbackReply* Reply(); + status_t GetAttr(status_t status, int mask, + uint64 size, uint64 change); status_t Recall(status_t status); private: diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestInterpreter.cpp b/src/add-ons/kernel/file_systems/nfs4/RequestInterpreter.cpp index c129cde78d..11ca0a235b 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestInterpreter.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RequestInterpreter.cpp @@ -28,6 +28,40 @@ RequestInterpreter::~RequestInterpreter() } +status_t +RequestInterpreter::GetAttr(FileHandle* handle, int* _mask) +{ + if (fLastOperation != OpCallbackGetAttr) + return B_BAD_VALUE; + + uint32 size; + const void* ptr = fRequest->Stream().GetOpaque(&size); + handle->fSize = size; + memcpy(handle->fData, ptr, size); + + uint32 count = fRequest->Stream().GetUInt(); + if (count < 1) { + *_mask = 0; + return fRequest->Stream().IsEOF() ? B_BAD_VALUE : B_OK; + } + + uint32 bitmap = fRequest->Stream().GetUInt(); + uint32 mask = 0; + + if ((bitmap & (1 << FATTR4_CHANGE)) != 0) + mask |= CallbackAttrChange; + if ((bitmap & (1 << FATTR4_SIZE)) != 0) + mask |= CallbackAttrSize; + + *_mask = mask; + + for (uint32 i = 1; i < count; i++) + fRequest->Stream().GetUInt(); + + return fRequest->Stream().IsEOF() ? B_BAD_VALUE : B_OK; +} + + status_t RequestInterpreter::Recall(FileHandle* handle, bool& truncate, uint32* stateSeq, uint32* stateID) diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestInterpreter.h b/src/add-ons/kernel/file_systems/nfs4/RequestInterpreter.h index 5febb48399..a17f2cebd7 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestInterpreter.h +++ b/src/add-ons/kernel/file_systems/nfs4/RequestInterpreter.h @@ -24,6 +24,7 @@ public: inline uint32 OperationCount(); inline uint32 Operation(); + status_t GetAttr(FileHandle* handle, int* mask); status_t Recall(FileHandle* handle, bool& truncate, uint32* stateSeq, uint32* stateID); From 49935f9b4f55bfad77098bf6e2652c8163760bd6 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Tue, 7 Aug 2012 00:22:34 +0200 Subject: [PATCH 172/252] nfs4: Check if user is allowed to use open state --- .../kernel/file_systems/nfs4/Inode.cpp | 13 +++++++--- src/add-ons/kernel/file_systems/nfs4/Inode.h | 2 ++ .../kernel/file_systems/nfs4/InodeRegular.cpp | 26 ++++++++++++------- 3 files changed, 28 insertions(+), 13 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index 1121a6e765..c86d104c2d 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -805,13 +805,20 @@ Inode::ReturnDelegation(bool truncate) MutexLocker stateLocker(fStateLock); fOpenState->fDelegation = NULL; + ReleaseOpenState(); + + delete fDelegation; + fDelegation = NULL; +} + + +void +Inode::ReleaseOpenState() +{ if (fOpenState->ReleaseReference() == 1) { fFileSystem->RemoveOpenFile(fOpenState); fOpenState = NULL; } - - delete fDelegation; - fDelegation = NULL; } diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h b/src/add-ons/kernel/file_systems/nfs4/Inode.h index 6dce7ba4cf..b30f33f1a9 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -93,6 +93,8 @@ public: protected: Inode(); + void ReleaseOpenState(); + status_t CreateState(const char* name, int mode, int perms, OpenState* state, OpenDelegationData* data); diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp index a4dcd76d96..a4f69678c3 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp @@ -130,13 +130,24 @@ Inode::Open(int mode, OpenFileCookie* cookie) status_t result = OpenFile(fOpenState, O_RDWR, &data); if (result != B_OK) { locker.Lock(); - if (fOpenState->ReleaseReference() == 1) { - fFileSystem->RemoveOpenFile(fOpenState); - fOpenState = NULL; - } + ReleaseOpenState(); return result; } fOpenState->fMode = O_RDWR; + } else { + int newMode = mode & O_RWMASK; + uint32 allowed = 0; + if (newMode == O_RDWR || newMode == O_RDONLY) + allowed |= R_OK; + if (newMode == O_RDWR || newMode == O_WRONLY) + allowed |= W_OK; + + status_t result = Access(allowed); + if (result != B_OK) { + locker.Lock(); + ReleaseOpenState(); + return result; + } } } @@ -173,12 +184,7 @@ Inode::Close(OpenFileCookie* cookie) SyncAndCommit(); MutexLocker _(fStateLock); - if (cookie->fOpenState != NULL) { - if (cookie->fOpenState->ReleaseReference() == 1) { - fFileSystem->RemoveOpenFile(fOpenState); - fOpenState = NULL; - } - } + ReleaseOpenState(); return B_OK; } From d8e2263f3b34a3ed39fdf96f96197e61abe3b3ad Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Tue, 7 Aug 2012 00:56:15 +0200 Subject: [PATCH 173/252] nfs4: Fix callback connection closing --- src/add-ons/kernel/file_systems/nfs4/Connection.cpp | 2 +- .../kernel/file_systems/nfs4/RPCCallbackServer.cpp | 13 ++++++++++++- .../kernel/file_systems/nfs4/RPCCallbackServer.h | 2 ++ 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Connection.cpp b/src/add-ons/kernel/file_systems/nfs4/Connection.cpp index 322ef47a7c..cc4611b9d8 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Connection.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Connection.cpp @@ -163,7 +163,7 @@ ServerAddress::InAddr() const status_t ServerAddress::ResolveName(const char* name, ServerAddress* address) { - address->fProtocol = IPPROTO_UDP; + address->fProtocol = IPPROTO_TCP; // getaddrinfo() is very expensive when called from kernel, so we do not // want to call it unless there is no other choice. diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCCallbackServer.cpp b/src/add-ons/kernel/file_systems/nfs4/RPCCallbackServer.cpp index 54fd3d346f..4039c08496 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RPCCallbackServer.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RPCCallbackServer.cpp @@ -143,6 +143,10 @@ CallbackServer::StopServer() ConnectionEntry* entry = fConnectionList; fConnectionList = entry->fNext; entry->fConnection->Disconnect(); + + status_t result; + wait_for_thread(entry->fThread, &result); + delete entry->fConnection; delete entry; } @@ -163,6 +167,8 @@ CallbackServer::NewConnection(Connection* connection) MutexLocker locker(fConnectionLock); entry->fNext = fConnectionList; + if (fConnectionList != NULL) + fConnectionList->fPrev = entry; fConnectionList = entry; locker.Unlock(); @@ -177,13 +183,17 @@ CallbackServer::NewConnection(Connection* connection) thread = spawn_kernel_thread(&CallbackServer::ConnectionThreadLauncher, "NFSv4 Callback Connection", B_NORMAL_PRIORITY, arguments); if (thread < B_OK) { + ReleaseConnection(entry); free(arguments); return thread; } + entry->fThread = thread; + status_t result = resume_thread(thread); if (result != B_OK) { kill_thread(thread); + ReleaseConnection(entry); free(arguments); return result; } @@ -232,7 +242,8 @@ CallbackServer::ConnectionThread(ConnectionEntry* entry) void* buffer; status_t result = connection->Receive(&buffer, &size); if (result != B_OK) { - ReleaseConnection(entry); + if (result != ECONNABORTED) + ReleaseConnection(entry); return result; } diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCCallbackServer.h b/src/add-ons/kernel/file_systems/nfs4/RPCCallbackServer.h index 9b22f20e05..d114c652de 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RPCCallbackServer.h +++ b/src/add-ons/kernel/file_systems/nfs4/RPCCallbackServer.h @@ -20,6 +20,8 @@ class Callback; struct ConnectionEntry { Connection* fConnection; + thread_id fThread; + ConnectionEntry* fNext; ConnectionEntry* fPrev; }; From 3ae5e813c43fe9602bbc5a06ee3821887f9e17cb Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Wed, 8 Aug 2012 03:48:35 +0200 Subject: [PATCH 174/252] nfs4: Implement node monitoring --- .../file_systems/nfs4/DirectoryCache.cpp | 72 ++++++++++++++++++- .../kernel/file_systems/nfs4/DirectoryCache.h | 4 ++ .../kernel/file_systems/nfs4/Inode.cpp | 15 +++- src/add-ons/kernel/file_systems/nfs4/Inode.h | 7 +- .../kernel/file_systems/nfs4/InodeRegular.cpp | 2 + .../file_systems/nfs4/MetadataCache.cpp | 46 +++++++++++- .../kernel/file_systems/nfs4/MetadataCache.h | 13 +++- .../kernel/file_systems/nfs4/NFS4Inode.cpp | 22 +++++- .../kernel/file_systems/nfs4/NFS4Inode.h | 2 +- 9 files changed, 171 insertions(+), 12 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.cpp b/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.cpp index dbb10f0c50..2e571664e3 100644 --- a/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.cpp @@ -175,7 +175,77 @@ DirectoryCache::Revalidate() return B_OK; } + DirectoryCacheSnapshot* oldSnapshot = fDirectoryCache; + oldSnapshot->AcquireReference(); + Trash(); - return B_ERROR; + + DirectoryCacheSnapshot* newSnapshot; + status_t result = fInode->GetDirSnapshot(&newSnapshot, NULL, &fChange); + if (result != B_OK) { + oldSnapshot->ReleaseReference(); + return B_OK; + } + newSnapshot->AcquireReference(); + + SetSnapshot(newSnapshot); + fExpireTime = system_time() + kExpirationTime; + fTrashed = false; + + NotifyChanges(oldSnapshot, newSnapshot); + oldSnapshot->ReleaseReference(); + newSnapshot->ReleaseReference(); + + return B_OK; +} + + +void +DirectoryCache::NotifyChanges(DirectoryCacheSnapshot* oldSnapshot, + DirectoryCacheSnapshot* newSnapshot) +{ + MutexLocker _(newSnapshot->fLock); + + SinglyLinkedList::Iterator oldIt + = oldSnapshot->fEntries.GetIterator(); + NameCacheEntry* oldCurrent; + + SinglyLinkedList::Iterator newIt + = newSnapshot->fEntries.GetIterator(); + NameCacheEntry* newCurrent = newIt.Next(); + while (newCurrent != NULL) { + oldIt = oldSnapshot->fEntries.GetIterator(); + oldCurrent = oldIt.Next(); + + bool found = false; + NameCacheEntry* prev = NULL; + while (oldCurrent != NULL) { + if (oldCurrent->fNode == newCurrent->fNode && + strcmp(oldCurrent->fName, newCurrent->fName) == 0) { + found = true; + break; + } + + prev = oldCurrent; + oldCurrent = oldIt.Next(); + } + + if (!found) { + notify_entry_created(fInode->GetFileSystem()->DevId(), + fInode->ID(), newCurrent->fName, newCurrent->fNode); + } else + oldSnapshot->fEntries.Remove(prev, oldCurrent); + + newCurrent = newIt.Next(); + } + + oldIt = oldSnapshot->fEntries.GetIterator(); + oldCurrent = oldIt.Next(); + + while (oldCurrent != NULL) { + notify_entry_removed(fInode->GetFileSystem()->DevId(), fInode->ID(), + oldCurrent->fName, oldCurrent->fNode); + oldCurrent = oldIt.Next(); + } } diff --git a/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.h b/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.h index e558b166e9..3f22e47c4b 100644 --- a/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.h +++ b/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.h @@ -65,6 +65,10 @@ public: inline time_t ExpireTime(); static const bigtime_t kExpirationTime = 15000000; +protected: + void NotifyChanges(DirectoryCacheSnapshot* oldSnapshot, + DirectoryCacheSnapshot* newSnapshot); + private: SinglyLinkedList fNameCache; diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index c86d104c2d..be97c45558 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -22,6 +22,7 @@ Inode::Inode() : + fMetaCache(this), fCache(NULL), fDelegation(NULL), fFileCache(NULL), @@ -248,6 +249,8 @@ Inode::Link(Inode* dir, const char* name) dir->fCache->Unlock(); } + notify_entry_created(fFileSystem->DevId(), dir->ID(), name, ID()); + return B_OK; } @@ -256,7 +259,8 @@ status_t Inode::Remove(const char* name, FileType type) { ChangeInfo changeInfo; - status_t result = NFS4Inode::RemoveObject(name, type, &changeInfo); + uint64 fileID; + status_t result = NFS4Inode::RemoveObject(name, type, &changeInfo, &fileID); if (result != B_OK) return result; @@ -272,6 +276,9 @@ Inode::Remove(const char* name, FileType type) fFileSystem->Root()->MakeInfoInvalid(); + notify_entry_removed(fFileSystem->DevId(), ID(), name, + FileIdToInoT(fileID)); + return B_OK; } @@ -311,6 +318,9 @@ Inode::Rename(Inode* from, Inode* to, const char* fromName, const char* toName) to->fCache->Unlock(); } + notify_entry_moved(from->fFileSystem->DevId(), from->ID(), fromName, + to->ID(), toName, FileIdToInoT(fileID)); + return B_OK; } @@ -349,6 +359,9 @@ Inode::CreateObject(const char* name, const char* path, int mode, FileType type) fCache->Unlock(); } + notify_entry_created(fFileSystem->DevId(), ID(), name, + FileIdToInoT(fileID)); + 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 b30f33f1a9..35dc4d8bbe 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -90,6 +90,10 @@ public: const struct flock* lock); status_t ReleaseAllLocks(OpenFileCookie* cookie); + status_t GetDirSnapshot(DirectoryCacheSnapshot** + _snapshot, OpenDirCookie* cookie, + uint64* _change); + protected: Inode(); @@ -105,9 +109,6 @@ protected: uint32 size); status_t FillDirEntry(struct dirent* de, ino_t id, const char* name, uint32 pos, uint32 size); - status_t GetDirSnapshot(DirectoryCacheSnapshot** - _snapshot, OpenDirCookie* cookie, - uint64* _change); status_t ChildAdded(const char* name, uint64 fileID, const FileHandle& fileHandle); diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp index a4f69678c3..7bad21a6f5 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp @@ -90,6 +90,8 @@ Inode::Create(const char* name, int mode, int perms, OpenFileCookie* cookie, fFileSystem->AddOpenFile(state); fFileSystem->Root()->MakeInfoInvalid(); + notify_entry_created(fFileSystem->DevId(), ID(), name, *id); + return B_OK; } diff --git a/src/add-ons/kernel/file_systems/nfs4/MetadataCache.cpp b/src/add-ons/kernel/file_systems/nfs4/MetadataCache.cpp index 058ce243c2..901021c47a 100644 --- a/src/add-ons/kernel/file_systems/nfs4/MetadataCache.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/MetadataCache.cpp @@ -9,11 +9,17 @@ #include "MetadataCache.h" +#include -MetadataCache::MetadataCache() +#include "Inode.h" + + +MetadataCache::MetadataCache(Inode* inode) : fExpire(0), - fForceValid(false) + fForceValid(false), + fInode(inode), + fInited(false) { mutex_init(&fLock, NULL); } @@ -52,8 +58,12 @@ void MetadataCache::SetStat(const struct stat& st) { MutexLocker _(fLock); + if (fInited) + NotifyChanges(&fStatCache, &st); + fStatCache = st; fExpire = time(NULL) + kExpirationTime; + fInited = true; } @@ -121,3 +131,35 @@ MetadataCache::UnlockValid() } +void +MetadataCache::NotifyChanges(const struct stat* oldStat, + const struct stat* newStat) +{ + uint32 flags = 0; + if (oldStat->st_size != newStat->st_size) + flags |= B_STAT_SIZE; + if (oldStat->st_mode != newStat->st_mode) + flags |= B_STAT_MODE; + if (oldStat->st_uid != newStat->st_uid) + flags |= B_STAT_UID; + if (oldStat->st_gid != newStat->st_gid) + flags |= B_STAT_GID; + + if (memcmp(&oldStat->st_atim, &newStat->st_atim, + sizeof(struct timespec) == 0)) + flags |= B_STAT_ACCESS_TIME; + + if (memcmp(&oldStat->st_ctim, &newStat->st_ctim, + sizeof(struct timespec) == 0)) + flags |= B_STAT_CHANGE_TIME; + + if (memcmp(&oldStat->st_crtim, &newStat->st_crtim, + sizeof(struct timespec) == 0)) + flags |= B_STAT_CREATION_TIME; + + if (memcmp(&oldStat->st_mtim, &newStat->st_mtim, + sizeof(struct timespec) == 0)) + flags |= B_STAT_MODIFICATION_TIME; + + notify_stat_changed(fInode->GetFileSystem()->DevId(), fInode->ID(), flags); +} diff --git a/src/add-ons/kernel/file_systems/nfs4/MetadataCache.h b/src/add-ons/kernel/file_systems/nfs4/MetadataCache.h index 4622c9e7dd..26a5e971f1 100644 --- a/src/add-ons/kernel/file_systems/nfs4/MetadataCache.h +++ b/src/add-ons/kernel/file_systems/nfs4/MetadataCache.h @@ -9,12 +9,15 @@ #define METADATACACHE_H +#include #include #include #include #include +class Inode; + struct AccessEntry { time_t fExpire; uint32 fAllowed; @@ -22,7 +25,7 @@ struct AccessEntry { class MetadataCache { public: - MetadataCache(); + MetadataCache(Inode* inode); ~MetadataCache(); status_t GetStat(struct stat* st); @@ -41,11 +44,19 @@ public: inline void Invalidate(); static const time_t kExpirationTime = 60; + +protected: + void NotifyChanges(const struct stat* oldStat, + const struct stat* newStat); + private: struct stat fStatCache; time_t fExpire; bool fForceValid; + Inode* fInode; + bool fInited; + AVLTreeMap fAccessCache; mutex fLock; diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp index a424350b29..24bb38d269 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp @@ -736,7 +736,8 @@ NFS4Inode::CreateObject(const char* name, const char* path, int mode, status_t -NFS4Inode::RemoveObject(const char* name, FileType type, ChangeInfo* changeInfo) +NFS4Inode::RemoveObject(const char* name, FileType type, ChangeInfo* changeInfo, + uint64* fileID) { do { RPC::Server* serv = fFileSystem->Server(); @@ -755,6 +756,10 @@ NFS4Inode::RemoveObject(const char* name, FileType type, ChangeInfo* changeInfo) req.Nverify(&attr, 1); req.PutFH(fInfo.fHandle); + + Attribute idAttr[] = { FATTR4_FILEID }; + req.GetAttr(idAttr, sizeof(idAttr) / sizeof(Attribute)); + req.Remove(name); status_t result = request.Send(); @@ -785,6 +790,18 @@ NFS4Inode::RemoveObject(const char* name, FileType type, ChangeInfo* changeInfo) reply.PutFH(); + AttrValue* values; + uint32 count; + result = reply.GetAttr(&values, &count); + if (result != B_OK) + return result; + + if (count == 0) + *fileID = fFileSystem->AllocFileId(); + else + *fileID = values[0].fData.fValue64; + delete[] values; + return reply.Remove(&changeInfo->fBefore, &changeInfo->fAfter, changeInfo->fAtomic); } while (true); @@ -831,8 +848,7 @@ NFS4Inode::ReadDirOnce(DirEntry** dirents, uint32* count, OpenDirCookie* cookie, return result; } - result = reply.ReadDir(dirCookie, dirCookieVerf, dirents, - count, eof); + result = reply.ReadDir(dirCookie, dirCookieVerf, dirents, count, eof); if (result != B_OK) { delete[] before; return result; diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h index 3e1bedb429..f340a42b3c 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h @@ -62,7 +62,7 @@ protected: int mode, FileType type, ChangeInfo* changeInfo, uint64* fileID, FileHandle* handle); status_t RemoveObject(const char* name, FileType type, - ChangeInfo* changeInfo); + ChangeInfo* changeInfo, uint64* fileID); status_t ReadDirOnce(DirEntry** dirents, uint32* count, OpenDirCookie* cookie, bool* eof, uint64* change, From 8ba78bf323c42caf3f72266afb55b617db1be5c5 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Thu, 9 Aug 2012 01:34:56 +0200 Subject: [PATCH 175/252] nfs4: Fix dir cookie rewinding --- src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) 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 f396be2df2..a146e0674e 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -601,9 +601,10 @@ nfs4_read_dir(fs_volume* volume, fs_vnode* vnode, void* _cookie, static status_t nfs4_rewind_dir(fs_volume* volume, fs_vnode* vnode, void* _cookie) { - uint64* cookie = reinterpret_cast(_cookie); - cookie[0] = 0; - cookie[1] = 2; + OpenDirCookie* cookie = reinterpret_cast(_cookie); + cookie->fSpecial = 0; + cookie->fCurrent = NULL; + cookie->fEOF = false; return B_OK; } From f7c35cf464752e44ce966c9a12d61882f5387611 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Thu, 9 Aug 2012 02:37:04 +0200 Subject: [PATCH 176/252] nfs4: Add attribute directory related hooks --- src/add-ons/kernel/file_systems/nfs4/Cookie.h | 2 + .../file_systems/nfs4/DirectoryCache.cpp | 35 ++++++++--- .../kernel/file_systems/nfs4/DirectoryCache.h | 3 +- .../kernel/file_systems/nfs4/FileInfo.h | 2 + .../kernel/file_systems/nfs4/Inode.cpp | 4 ++ src/add-ons/kernel/file_systems/nfs4/Inode.h | 3 + .../kernel/file_systems/nfs4/InodeDir.cpp | 59 ++++++++++++++----- .../kernel/file_systems/nfs4/NFS4Defs.h | 1 + .../kernel/file_systems/nfs4/NFS4Inode.cpp | 36 ++++++++++- .../kernel/file_systems/nfs4/NFS4Inode.h | 2 + .../file_systems/nfs4/ReplyInterpreter.h | 8 +++ .../file_systems/nfs4/RequestBuilder.cpp | 17 ++++++ .../kernel/file_systems/nfs4/RequestBuilder.h | 1 + .../file_systems/nfs4/kernel_interface.cpp | 56 ++++++++++++++++-- 14 files changed, 199 insertions(+), 30 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Cookie.h b/src/add-ons/kernel/file_systems/nfs4/Cookie.h index 1fd8c9c29a..0f57b822bb 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Cookie.h +++ b/src/add-ons/kernel/file_systems/nfs4/Cookie.h @@ -92,6 +92,8 @@ struct OpenDirCookie : public Cookie { NameCacheEntry* fCurrent; bool fEOF; + bool fAttrDir; + ~OpenDirCookie(); }; diff --git a/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.cpp b/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.cpp index 2e571664e3..eb8ca9ab8b 100644 --- a/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.cpp @@ -10,6 +10,7 @@ #include "DirectoryCache.h" #include +#include #include "Inode.h" @@ -46,10 +47,11 @@ DirectoryCacheSnapshot::~DirectoryCacheSnapshot() } -DirectoryCache::DirectoryCache(Inode* inode) +DirectoryCache::DirectoryCache(Inode* inode, bool attr) : fDirectoryCache(NULL), fInode(inode), + fAttrDir(attr), fTrashed(true) { mutex_init(&fLock, NULL); @@ -114,8 +116,12 @@ DirectoryCache::AddEntry(const char* name, ino_t node, bool created) fDirectoryCache->fEntries.Add(entry); } - return entry_cache_add(fInode->GetFileSystem()->DevId(), fInode->ID(), name, - node); + if (!fAttrDir) { + return entry_cache_add(fInode->GetFileSystem()->DevId(), fInode->ID(), + name, node); + } + + return B_OK; } void @@ -153,7 +159,10 @@ DirectoryCache::RemoveEntry(const char* name) } } - entry_cache_remove(fInode->GetFileSystem()->DevId(), fInode->ID(), name); + if (!fAttrDir) { + entry_cache_remove(fInode->GetFileSystem()->DevId(), fInode->ID(), + name); + } } @@ -231,8 +240,13 @@ DirectoryCache::NotifyChanges(DirectoryCacheSnapshot* oldSnapshot, } if (!found) { - notify_entry_created(fInode->GetFileSystem()->DevId(), - fInode->ID(), newCurrent->fName, newCurrent->fNode); + if (fAttrDir) { + notify_attribute_changed(fInode->GetFileSystem()->DevId(), + fInode->ID(), newCurrent->fName, B_ATTR_CREATED); + } else { + notify_entry_created(fInode->GetFileSystem()->DevId(), + fInode->ID(), newCurrent->fName, newCurrent->fNode); + } } else oldSnapshot->fEntries.Remove(prev, oldCurrent); @@ -243,8 +257,13 @@ DirectoryCache::NotifyChanges(DirectoryCacheSnapshot* oldSnapshot, oldCurrent = oldIt.Next(); while (oldCurrent != NULL) { - notify_entry_removed(fInode->GetFileSystem()->DevId(), fInode->ID(), - oldCurrent->fName, oldCurrent->fNode); + if (fAttrDir) { + notify_attribute_changed(fInode->GetFileSystem()->DevId(), + fInode->ID(), newCurrent->fName, B_ATTR_REMOVED); + } else { + notify_entry_removed(fInode->GetFileSystem()->DevId(), fInode->ID(), + oldCurrent->fName, oldCurrent->fNode); + } oldCurrent = oldIt.Next(); } } diff --git a/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.h b/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.h index 3f22e47c4b..ac152f0158 100644 --- a/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.h +++ b/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.h @@ -37,7 +37,7 @@ struct DirectoryCacheSnapshot : public KernelReferenceable { class DirectoryCache : public DoublyLinkedListLinkImpl { public: - DirectoryCache(Inode* inode); + DirectoryCache(Inode* inode, bool attr = false); ~DirectoryCache(); inline status_t Lock(); @@ -76,6 +76,7 @@ private: Inode* fInode; + bool fAttrDir; bool fTrashed; mutex fLock; diff --git a/src/add-ons/kernel/file_systems/nfs4/FileInfo.h b/src/add-ons/kernel/file_systems/nfs4/FileInfo.h index 5cd0f2af3c..47c377ddc8 100644 --- a/src/add-ons/kernel/file_systems/nfs4/FileInfo.h +++ b/src/add-ons/kernel/file_systems/nfs4/FileInfo.h @@ -44,6 +44,8 @@ struct FileInfo { const char* fName; const char* fPath; + FileHandle fAttrDir; + inline FileInfo(); inline ~FileInfo(); inline FileInfo(const FileInfo& fi); diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index be97c45558..805ba5ae9c 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -24,6 +24,7 @@ Inode::Inode() : fMetaCache(this), fCache(NULL), + fAttrCache(NULL), fDelegation(NULL), fFileCache(NULL), fMaxFileSize(0), @@ -93,6 +94,7 @@ Inode::CreateInode(FileSystem* fs, const FileInfo &fi, Inode** _inode) if (inode->fType == NF4DIR) inode->fCache = new DirectoryCache(inode); + inode->fAttrCache = new DirectoryCache(inode, true); // FATTR4_CHANGE is mandatory inode->fChange = values[1].fData.fValue64; @@ -131,6 +133,8 @@ Inode::~Inode() file_cache_delete(fFileCache); delete fCache; + delete fAttrCache; + mutex_destroy(&fStateLock); mutex_destroy(&fFileCacheLock); rw_lock_destroy(&fDelegationLock); diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h b/src/add-ons/kernel/file_systems/nfs4/Inode.h index 35dc4d8bbe..03a03ace65 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -82,6 +82,8 @@ public: status_t ReadDir(void* buffer, uint32 size, uint32* count, OpenDirCookie* cookie); + status_t OpenAttrDir(OpenDirCookie* cookie); + status_t TestLock(OpenFileCookie* cookie, struct flock* lock); status_t AcquireLock(OpenFileCookie* cookie, @@ -124,6 +126,7 @@ private: MetadataCache fMetaCache; DirectoryCache* fCache; + DirectoryCache* fAttrCache; rw_lock fDelegationLock; Delegation* fDelegation; diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp b/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp index c303678c9b..b4d1a9e0d8 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp @@ -39,11 +39,36 @@ Inode::OpenDir(OpenDirCookie* cookie) cookie->fSnapshot = NULL; cookie->fCurrent = NULL; cookie->fEOF = false; + cookie->fAttrDir = false; return B_OK; } +status_t +Inode::OpenAttrDir(OpenDirCookie* cookie) +{ + cookie->fFileSystem = fFileSystem; + cookie->fSpecial = 0; + cookie->fSnapshot = NULL; + cookie->fCurrent = NULL; + cookie->fEOF = false; + cookie->fAttrDir = true; + + if (fInfo.fAttrDir.fSize == 0) { + FileHandle handle; + + status_t result = NFS4Inode::OpenAttrDir(&handle); + if (result != B_OK) + return result; + + fInfo.fAttrDir = handle; + } + + return B_OK; +} + + status_t Inode::FillDirEntry(struct dirent* de, ino_t id, const char* name, uint32 pos, uint32 size) @@ -152,10 +177,13 @@ Inode::GetDirSnapshot(DirectoryCacheSnapshot** _snapshot, continue; ino_t id; - if (dirents[i].fAttrCount == 2) - id = FileIdToInoT(dirents[i].fAttrs[1].fData.fValue64); - else - id = FileIdToInoT(fFileSystem->AllocFileId()); + if (!cookie->fAttrDir) { + if (dirents[i].fAttrCount == 2) + id = FileIdToInoT(dirents[i].fAttrs[1].fData.fValue64); + else + id = FileIdToInoT(fFileSystem->AllocFileId()); + } else + id = 0; NameCacheEntry* entry = new NameCacheEntry(dirents[i].fName, id); if (entry == NULL || entry->fName == NULL) { @@ -188,29 +216,30 @@ Inode::ReadDir(void* _buffer, uint32 size, uint32* _count, } status_t result; + DirectoryCache* cache = cookie->fAttrDir ? fAttrCache : fCache; if (cookie->fSnapshot == NULL) { fFileSystem->Revalidator().Lock(); - if (fCache->Lock() != B_OK) { - fCache->ResetAndLock(); + if (cache->Lock() != B_OK) { + cache->ResetAndLock(); } else { - fFileSystem->Revalidator().RemoveDirectory(fCache); + fFileSystem->Revalidator().RemoveDirectory(cache); } - cookie->fSnapshot = fCache->GetSnapshot(); + cookie->fSnapshot = cache->GetSnapshot(); if (cookie->fSnapshot == NULL) { uint64 change; result = GetDirSnapshot(&cookie->fSnapshot, cookie, &change); if (result != B_OK) { - fCache->Unlock(); + cache->Unlock(); fFileSystem->Revalidator().Unlock(); return result; } - fCache->ValidateChangeInfo(change); - fCache->SetSnapshot(cookie->fSnapshot); + cache->ValidateChangeInfo(change); + cache->SetSnapshot(cookie->fSnapshot); } cookie->fSnapshot->AcquireReference(); - fFileSystem->Revalidator().AddDirectory(fCache); - fCache->Unlock(); + fFileSystem->Revalidator().AddDirectory(cache); + cache->Unlock(); fFileSystem->Revalidator().Unlock(); } @@ -219,7 +248,7 @@ Inode::ReadDir(void* _buffer, uint32 size, uint32* _count, uint32 i = 0; bool overflow = false; - if (cookie->fSpecial == 0 && i < *_count) { + if (cookie->fSpecial == 0 && i < *_count && !cookie->fAttrDir) { struct dirent* de = reinterpret_cast(buffer + pos); status_t result; @@ -235,7 +264,7 @@ Inode::ReadDir(void* _buffer, uint32 size, uint32* _count, return result; } - if (cookie->fSpecial == 1 && i < *_count) { + if (cookie->fSpecial == 1 && i < *_count && !cookie->fAttrDir) { struct dirent* de = reinterpret_cast(buffer + pos); status_t result; diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h index e60b45cd1e..1a617ff67f 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h @@ -46,6 +46,7 @@ enum Opcode { OpLookUpUp = 16, OpNverify = 17, OpOpen = 18, + OpOpenAttrDir = 19, OpOpenConfirm = 20, OpPutFH = 22, OpPutRootFH = 24, diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp index 24bb38d269..aca6514b6f 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp @@ -817,7 +817,10 @@ NFS4Inode::ReadDirOnce(DirEntry** dirents, uint32* count, OpenDirCookie* cookie, Request request(serv); RequestBuilder& req = request.Builder(); - req.PutFH(fInfo.fHandle); + if (cookie->fAttrDir) + req.PutFH(fInfo.fAttrDir); + else + req.PutFH(fInfo.fHandle); Attribute dirAttr[] = { FATTR4_CHANGE }; if (*change == 0) @@ -875,6 +878,37 @@ NFS4Inode::ReadDirOnce(DirEntry** dirents, uint32* count, OpenDirCookie* cookie, } +status_t +NFS4Inode::OpenAttrDir(FileHandle* handle) +{ + do { + RPC::Server* serv = fFileSystem->Server(); + Request request(serv); + RequestBuilder& req = request.Builder(); + + req.PutFH(fInfo.fHandle); + req.OpenAttrDir(true); + req.GetFH(); + + status_t result = request.Send(); + if (result != B_OK) + return result; + + ReplyInterpreter& reply = request.Reply(); + + if (HandleErrors(reply.NFS4Error(), serv)) + continue; + + reply.PutFH(); + result = reply.OpenAttrDir(); + if (result != B_OK) + return result; + + return reply.GetFH(handle); + } while (true); +} + + status_t NFS4Inode::TestLock(OpenFileCookie* cookie, LockType* type, uint64* position, uint64* length, bool& conflict) diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h index f340a42b3c..d7cd36669a 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h @@ -68,6 +68,8 @@ protected: OpenDirCookie* cookie, bool* eof, uint64* change, uint64* dirCookie, uint64* dirCookieVerf); + status_t OpenAttrDir(FileHandle* handle); + status_t TestLock(OpenFileCookie* cookie, LockType* type, uint64* position, uint64* length, bool& conflict); status_t AcquireLock(OpenFileCookie* cookie, LockInfo* lockInfo, diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h index 986fcd8a7c..b630b8ffb9 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h @@ -84,6 +84,7 @@ public: status_t Open(uint32* id, uint32* seq, bool* confirm, OpenDelegationData* delegData, ChangeInfo* changeInfo = NULL); + inline status_t OpenAttrDir(); status_t OpenConfirm(uint32* stateSeq); inline status_t PutFH(); inline status_t PutRootFH(); @@ -172,6 +173,13 @@ ReplyInterpreter::LookUpUp() } +inline status_t +ReplyInterpreter::OpenAttrDir() +{ + return _OperationError(OpOpenAttrDir); +} + + inline status_t ReplyInterpreter::Nverify() { diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp index 08f4dff29c..04add4c0e4 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp @@ -445,6 +445,23 @@ RequestBuilder::OpenConfirm(uint32 seq, const uint32* id, uint32 stateSeq) } +status_t +RequestBuilder::OpenAttrDir(bool create) +{ + if (fProcedure != ProcCompound) + return B_BAD_VALUE; + if (fRequest == NULL) + return B_NO_MEMORY; + + fRequest->Stream().AddUInt(OpOpenAttrDir); + fRequest->Stream().AddBoolean(create); + + fOpCount++; + + return B_OK; +} + + status_t RequestBuilder::PutFH(const FileHandle& fh) { diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h index d958d6d05a..9ef417413b 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h @@ -56,6 +56,7 @@ public: uint32 count = 0, bool excl = false, OpenDelegation delegType = OPEN_DELEGATE_NONE); + status_t OpenAttrDir(bool create); 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 a146e0674e..d62a9a4e98 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -610,6 +610,52 @@ nfs4_rewind_dir(fs_volume* volume, fs_vnode* vnode, void* _cookie) } +static status_t +nfs4_open_attr_dir(fs_volume* volume, fs_vnode* vnode, void** _cookie) +{ + OpenDirCookie* cookie = new(std::nothrow) OpenDirCookie; + if (cookie == NULL) + return B_NO_MEMORY; + *_cookie = cookie; + + Inode* inode = reinterpret_cast(vnode->private_node); + status_t result = inode->OpenAttrDir(cookie); + if (result != B_OK) + delete cookie; + + return result; +} + + +static status_t +nfs4_close_attr_dir(fs_volume* volume, fs_vnode* vnode, void* cookie) +{ + return nfs4_close_attr_dir(volume, vnode, cookie); +} + + +static status_t +nfs4_free_attr_dir_cookie(fs_volume* volume, fs_vnode* vnode, void* cookie) +{ + return nfs4_free_dir_cookie(volume, vnode, cookie); +} + + +static status_t +nfs4_read_attr_dir(fs_volume* volume, fs_vnode* vnode, void* cookie, + struct dirent* buffer, size_t bufferSize, uint32* _num) +{ + return nfs4_read_dir(volume, vnode, cookie, buffer, bufferSize, _num); +} + + +static status_t +nfs4_rewind_attr_dir(fs_volume* volume, fs_vnode* vnode, void* cookie) +{ + return nfs4_rewind_attr_dir(volume, vnode, cookie); +} + + static status_t nfs4_test_lock(fs_volume* volume, fs_vnode* vnode, void* _cookie, struct flock* lock) @@ -774,11 +820,11 @@ fs_vnode_ops gNFSv4VnodeOps = { nfs4_rewind_dir, /* attribute directory operations */ - NULL, // open_attr_dir - NULL, // close_attr_dir - NULL, // free_attr_dir_cookie - NULL, // read_attr_dir - NULL, // rewind_attr_dir + nfs4_open_attr_dir, + nfs4_close_attr_dir, + nfs4_free_attr_dir_cookie, + nfs4_read_attr_dir, + nfs4_rewind_attr_dir, /* attribute operations */ NULL, // create_attr From 2431c4521c4e3a2fb15d3440ee10ebc68c081bce Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Thu, 9 Aug 2012 17:18:41 +0200 Subject: [PATCH 177/252] nfs4: Make idmapper initialization lazy --- .../kernel/file_systems/nfs4/IdMap.cpp | 3 ++- src/add-ons/kernel/file_systems/nfs4/IdMap.h | 1 + .../file_systems/nfs4/kernel_interface.cpp | 19 ++++++++++++------- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/IdMap.cpp b/src/add-ons/kernel/file_systems/nfs4/IdMap.cpp index b53cbe9787..3a87315fb5 100644 --- a/src/add-ons/kernel/file_systems/nfs4/IdMap.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/IdMap.cpp @@ -16,7 +16,8 @@ #include "idmapper/IdMapper.h" -IdMap* gIdMapper = NULL; +IdMap* gIdMapper = NULL; +mutex gIdMapperLock; IdMap::IdMap() diff --git a/src/add-ons/kernel/file_systems/nfs4/IdMap.h b/src/add-ons/kernel/file_systems/nfs4/IdMap.h index 266bef6366..318f6dd777 100644 --- a/src/add-ons/kernel/file_systems/nfs4/IdMap.h +++ b/src/add-ons/kernel/file_systems/nfs4/IdMap.h @@ -41,6 +41,7 @@ private: }; extern IdMap* gIdMapper; +extern mutex gIdMapperLock; #endif // IDMAP_H 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 d62a9a4e98..17e1d7c8f5 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -76,6 +76,12 @@ nfs4_mount(fs_volume* volume, const char* device, uint32 flags, { status_t result; + MutexLocker locker(gIdMapperLock); + gIdMapper = new(std::nothrow) IdMap; + if (gIdMapper == NULL) + return B_NO_MEMORY; + locker.Unlock(); + ServerAddress address; char path[256]; result = ParseArguments(args, &address, path); @@ -706,23 +712,20 @@ nfs4_init() if (gRPCServerManager == NULL) return B_NO_MEMORY; - gIdMapper = new(std::nothrow) IdMap; - if (gIdMapper == NULL) { - delete gRPCServerManager; - return B_NO_MEMORY; - } + mutex_init(&gIdMapperLock, "idmapper Init Lock"); + gIdMapper = NULL; gWorkQueue = new(std::nothrow) WorkQueue; if (gWorkQueue == NULL || gWorkQueue->InitStatus() != B_OK) { delete gWorkQueue; - delete gIdMapper; + mutex_destroy(&gIdMapperLock); delete gRPCServerManager; return B_NO_MEMORY; } gRPCCallbackServer = new(std::nothrow) RPC::CallbackServer; if (gRPCCallbackServer == NULL) { - delete gIdMapper; + mutex_destroy(&gIdMapperLock); delete gWorkQueue; delete gRPCServerManager; return B_NO_MEMORY; @@ -742,6 +745,8 @@ nfs4_uninit() delete gWorkQueue; delete gRPCServerManager; + mutex_destroy(&gIdMapperLock); + return B_OK; } From 8afd81bae22fa09e14593b6fd5dd07695604a77c Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Thu, 9 Aug 2012 18:09:56 +0200 Subject: [PATCH 178/252] nfs4: Fix mounting server's root directory --- src/add-ons/kernel/file_systems/nfs4/FileInfo.cpp | 7 ++++--- src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp | 5 ++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/FileInfo.cpp b/src/add-ons/kernel/file_systems/nfs4/FileInfo.cpp index 22a86ecfbc..402c642356 100644 --- a/src/add-ons/kernel/file_systems/nfs4/FileInfo.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/FileInfo.cpp @@ -30,14 +30,15 @@ FileInfo::ParsePath(RequestBuilder& req, uint32& count, const char* _path) if (pathEnd != NULL) *pathEnd = '\0'; - req.LookUp(pathStart); + if (pathEnd != pathStart) { + req.LookUp(pathStart); + count++; + } if (pathEnd != NULL && pathEnd[1] != '\0') pathStart = pathEnd + 1; else pathStart = NULL; - - count++; } free(path); diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp b/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp index b4d1a9e0d8..08eb38b61d 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp @@ -268,9 +268,8 @@ Inode::ReadDir(void* _buffer, uint32 size, uint32* _count, struct dirent* de = reinterpret_cast(buffer + pos); status_t result; - if (strcmp(fInfo.fName, "/")) - result = ReadDirUp(de, pos, size); - else { + result = ReadDirUp(de, pos, size); + if (result == B_ENTRY_NOT_FOUND) { result = FillDirEntry(de, FileIdToInoT(fInfo.fFileId), "..", pos, size); } From 2314d073afc14b7a0e5a1eb27925658b9f2cc212 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Thu, 9 Aug 2012 19:24:32 +0200 Subject: [PATCH 179/252] nfs4: Inode::GetDirSnapshot should not require OpenDirCookie --- src/add-ons/kernel/file_systems/nfs4/DirectoryCache.cpp | 3 ++- src/add-ons/kernel/file_systems/nfs4/Inode.h | 2 +- src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp | 9 +++++---- src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp | 5 +++-- src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h | 3 ++- 5 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.cpp b/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.cpp index eb8ca9ab8b..909f62956a 100644 --- a/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.cpp @@ -190,7 +190,8 @@ DirectoryCache::Revalidate() Trash(); DirectoryCacheSnapshot* newSnapshot; - status_t result = fInode->GetDirSnapshot(&newSnapshot, NULL, &fChange); + status_t result = fInode->GetDirSnapshot(&newSnapshot, NULL, &fChange, + fAttrDir); if (result != B_OK) { oldSnapshot->ReleaseReference(); 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 03a03ace65..62fffcff80 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -94,7 +94,7 @@ public: status_t GetDirSnapshot(DirectoryCacheSnapshot** _snapshot, OpenDirCookie* cookie, - uint64* _change); + uint64* _change, bool attribute); protected: Inode(); diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp b/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp index 08eb38b61d..ac80441cb7 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp @@ -145,7 +145,7 @@ Inode::ReadDirUp(struct dirent* de, uint32 pos, uint32 size) status_t Inode::GetDirSnapshot(DirectoryCacheSnapshot** _snapshot, - OpenDirCookie* cookie, uint64* _change) + OpenDirCookie* cookie, uint64* _change, bool attribute) { DirectoryCacheSnapshot* snapshot = new DirectoryCacheSnapshot; if (snapshot == NULL) @@ -161,7 +161,7 @@ Inode::GetDirSnapshot(DirectoryCacheSnapshot** _snapshot, DirEntry* dirents; status_t result = ReadDirOnce(&dirents, &count, cookie, &eof, &change, - &dirCookie, &dirCookieVerf); + &dirCookie, &dirCookieVerf, attribute); if (result != B_OK) { delete snapshot; return result; @@ -177,7 +177,7 @@ Inode::GetDirSnapshot(DirectoryCacheSnapshot** _snapshot, continue; ino_t id; - if (!cookie->fAttrDir) { + if (!attribute) { if (dirents[i].fAttrCount == 2) id = FileIdToInoT(dirents[i].fAttrs[1].fData.fValue64); else @@ -228,7 +228,8 @@ Inode::ReadDir(void* _buffer, uint32 size, uint32* _count, cookie->fSnapshot = cache->GetSnapshot(); if (cookie->fSnapshot == NULL) { uint64 change; - result = GetDirSnapshot(&cookie->fSnapshot, cookie, &change); + result = GetDirSnapshot(&cookie->fSnapshot, cookie, &change, + cookie->fAttrDir); if (result != B_OK) { cache->Unlock(); fFileSystem->Revalidator().Unlock(); diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp index aca6514b6f..a026e18d5c 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp @@ -810,14 +810,15 @@ NFS4Inode::RemoveObject(const char* name, FileType type, ChangeInfo* changeInfo, status_t NFS4Inode::ReadDirOnce(DirEntry** dirents, uint32* count, OpenDirCookie* cookie, - bool* eof, uint64* change, uint64* dirCookie, uint64* dirCookieVerf) + bool* eof, uint64* change, uint64* dirCookie, uint64* dirCookieVerf, + bool attribute) { do { RPC::Server* serv = fFileSystem->Server(); Request request(serv); RequestBuilder& req = request.Builder(); - if (cookie->fAttrDir) + if (attribute) req.PutFH(fInfo.fAttrDir); else req.PutFH(fInfo.fHandle); diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h index d7cd36669a..fad2e89c53 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h @@ -66,7 +66,8 @@ protected: status_t ReadDirOnce(DirEntry** dirents, uint32* count, OpenDirCookie* cookie, bool* eof, uint64* change, - uint64* dirCookie, uint64* dirCookieVerf); + uint64* dirCookie, uint64* dirCookieVerf, + bool attribute); status_t OpenAttrDir(FileHandle* handle); From 29fb3a4af2fdd3fe1ac4a0824d83783eb1e8ad45 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Thu, 9 Aug 2012 20:46:45 +0200 Subject: [PATCH 180/252] nfs4: Fix receiving from stream transport protocols --- src/add-ons/kernel/file_systems/nfs4/Connection.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Connection.cpp b/src/add-ons/kernel/file_systems/nfs4/Connection.cpp index cc4611b9d8..6b38b04dab 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Connection.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Connection.cpp @@ -318,10 +318,10 @@ ConnectionStream::Receive(void** _buffer, uint32* _size) { status_t result; - int32 size = 0; + uint32 size = 0; void* buffer = NULL; - int32 record_size; + uint32 record_size; bool last_one; object_wait_info object[2]; @@ -359,7 +359,7 @@ ConnectionStream::Receive(void** _buffer, uint32* _size) } record_size = ntohl(record_size); - last_one = record_size < 0; + last_one = static_cast(record_size) < 0; record_size &= LAST_FRAGMENT - 1; void* ptr = realloc(buffer, size + record_size); @@ -374,7 +374,7 @@ ConnectionStream::Receive(void** _buffer, uint32* _size) result = recv(fSocket, (uint8*)buffer + size + received, record_size - received, 0); received += result; - } while (result > 0 && received < sizeof(record_size)); + } while (result > 0 && received < record_size); if (result < 0) { result = errno; free(buffer); From 20d1b02eefc137b62fac748323e6747c7f9e6ef3 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Thu, 9 Aug 2012 23:39:56 +0200 Subject: [PATCH 181/252] nfs4: Add basic support for extended attributes --- src/add-ons/kernel/file_systems/nfs4/Cookie.h | 7 +- .../kernel/file_systems/nfs4/Delegation.cpp | 7 +- .../kernel/file_systems/nfs4/Delegation.h | 3 +- .../kernel/file_systems/nfs4/FileInfo.h | 11 ++ .../kernel/file_systems/nfs4/Inode.cpp | 112 ++++++++----- src/add-ons/kernel/file_systems/nfs4/Inode.h | 24 ++- .../kernel/file_systems/nfs4/InodeDir.cpp | 9 +- .../kernel/file_systems/nfs4/InodeRegular.cpp | 86 +++++++++- .../file_systems/nfs4/MetadataCache.cpp | 6 +- .../kernel/file_systems/nfs4/MetadataCache.h | 2 + .../kernel/file_systems/nfs4/NFS4Inode.cpp | 154 +++++++++++++----- .../kernel/file_systems/nfs4/NFS4Inode.h | 15 +- .../kernel/file_systems/nfs4/NFS4Object.cpp | 2 +- .../kernel/file_systems/nfs4/NFS4Object.h | 4 +- .../file_systems/nfs4/RequestBuilder.cpp | 10 +- .../kernel/file_systems/nfs4/RequestBuilder.h | 2 +- .../file_systems/nfs4/kernel_interface.cpp | 142 ++++++++++++++-- 17 files changed, 475 insertions(+), 121 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Cookie.h b/src/add-ons/kernel/file_systems/nfs4/Cookie.h index 0f57b822bb..c8956eec58 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Cookie.h +++ b/src/add-ons/kernel/file_systems/nfs4/Cookie.h @@ -73,11 +73,12 @@ struct Cookie { status_t CancelAll(); }; -struct OpenFileCookie : public Cookie { +struct OpenStateCookie : public Cookie { OpenState* fOpenState; - uint32 fMode; +}; +struct OpenFileCookie : public OpenStateCookie { LockInfo* fLocks; void AddLock(LockInfo* lock); @@ -97,6 +98,8 @@ struct OpenDirCookie : public Cookie { ~OpenDirCookie(); }; +struct OpenAttrCookie : public OpenStateCookie { }; + #endif // COOKIE_H diff --git a/src/add-ons/kernel/file_systems/nfs4/Delegation.cpp b/src/add-ons/kernel/file_systems/nfs4/Delegation.cpp index 80aeb4330a..19ea2f2a63 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Delegation.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Delegation.cpp @@ -14,11 +14,12 @@ Delegation::Delegation(const OpenDelegationData& data, Inode* inode, - uint64 clientID) + uint64 clientID, bool attribute) : fClientID(clientID), fData(data), - fInode(inode) + fInode(inode), + fAttribute(attribute) { } @@ -26,7 +27,7 @@ Delegation::Delegation(const OpenDelegationData& data, Inode* inode, status_t Delegation::GiveUp(bool truncate) { - if (!truncate) + if (!fAttribute && !truncate) fInode->SyncAndCommit(true); ReturnDelegation(); diff --git a/src/add-ons/kernel/file_systems/nfs4/Delegation.h b/src/add-ons/kernel/file_systems/nfs4/Delegation.h index 19afcfb450..f901173d23 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Delegation.h +++ b/src/add-ons/kernel/file_systems/nfs4/Delegation.h @@ -21,7 +21,7 @@ class Delegation : public NFS4Object, public DoublyLinkedListLinkImpl { public: Delegation(const OpenDelegationData& data, Inode* inode, - uint64 clientID); + uint64 clientID, bool attr = false); status_t GiveUp(bool truncate = false); @@ -35,6 +35,7 @@ private: uint64 fClientID; OpenDelegationData fData; Inode* fInode; + bool fAttribute; }; diff --git a/src/add-ons/kernel/file_systems/nfs4/FileInfo.h b/src/add-ons/kernel/file_systems/nfs4/FileInfo.h index 47c377ddc8..ecacc0cace 100644 --- a/src/add-ons/kernel/file_systems/nfs4/FileInfo.h +++ b/src/add-ons/kernel/file_systems/nfs4/FileInfo.h @@ -25,6 +25,8 @@ struct FileHandle { inline FileHandle(const FileHandle& fh); inline FileHandle& operator=(const FileHandle& fh); + + inline bool operator!=(const FileHandle& handle) const; inline bool operator>(const FileHandle& handle) const; inline bool operator<(const FileHandle& handle) const; }; @@ -92,6 +94,15 @@ FileHandle::operator=(const FileHandle& fh) } +inline bool +FileHandle::operator!=(const FileHandle& handle) const +{ + if (fSize != handle.fSize) + return true; + return memcmp(fData, handle.fData, fSize) != 0; +} + + inline bool FileHandle::operator>(const FileHandle& handle) const { diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index 805ba5ae9c..b0af3541b3 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -262,68 +262,100 @@ Inode::Link(Inode* dir, const char* name) status_t Inode::Remove(const char* name, FileType type) { + if (type == NF4NAMEDATTR) { + status_t result = LoadAttrDirHandle(); + if (result != B_OK) + return result; + } + ChangeInfo changeInfo; uint64 fileID; status_t result = NFS4Inode::RemoveObject(name, type, &changeInfo, &fileID); if (result != B_OK) return result; - if (fCache->Lock() == B_OK) { + DirectoryCache* cache = type != NF4NAMEDATTR ? fCache : fAttrCache; + if (cache->Lock() == B_OK) { if (changeInfo.fAtomic && fCache->ChangeInfo() == changeInfo.fBefore) { - fCache->RemoveEntry(name); - fCache->SetChangeInfo(changeInfo.fAfter); - } else if (fCache->ChangeInfo() != changeInfo.fBefore) - fCache->Trash(); - fCache->Unlock(); + cache->RemoveEntry(name); + cache->SetChangeInfo(changeInfo.fAfter); + } else if (cache->ChangeInfo() != changeInfo.fBefore) + cache->Trash(); + cache->Unlock(); } fFileSystem->Root()->MakeInfoInvalid(); - notify_entry_removed(fFileSystem->DevId(), ID(), name, - FileIdToInoT(fileID)); + if (type == NF4NAMEDATTR) { + notify_attribute_changed(fFileSystem->DevId(), ID(), name, + B_ATTR_REMOVED); + } else { + notify_entry_removed(fFileSystem->DevId(), ID(), name, + FileIdToInoT(fileID)); + } return B_OK; } status_t -Inode::Rename(Inode* from, Inode* to, const char* fromName, const char* toName) +Inode::Rename(Inode* from, Inode* to, const char* fromName, const char* toName, + bool attribute) { if (from->fFileSystem != to->fFileSystem) return B_DONT_DO_THAT; + if (attribute) { + status_t result = from->LoadAttrDirHandle(); + if (result != B_OK) + return result; + + result = to->LoadAttrDirHandle(); + if (result != B_OK) + return result; + } + ChangeInfo fromChange, toChange; uint64 fileID; status_t result = NFS4Inode::Rename(from, to, fromName, toName, &fromChange, - &toChange, &fileID); + &toChange, &fileID, attribute); if (result != B_OK) return result; from->fFileSystem->Root()->MakeInfoInvalid(); - if (from->fCache->Lock() == B_OK) { + DirectoryCache* cache = attribute ? from->fAttrCache : from->fCache; + if (cache->Lock() == B_OK) { if (fromChange.fAtomic - && from->fCache->ChangeInfo() == fromChange.fBefore) { - from->fCache->RemoveEntry(fromName); - from->fCache->SetChangeInfo(fromChange.fAfter); - } else if (from->fCache->ChangeInfo() != fromChange.fBefore) - from->fCache->Trash(); - from->fCache->Unlock(); + && cache->ChangeInfo() == fromChange.fBefore) { + cache->RemoveEntry(fromName); + cache->SetChangeInfo(fromChange.fAfter); + } else if (cache->ChangeInfo() != fromChange.fBefore) + cache->Trash(); + cache->Unlock(); } - if (to->fCache->Lock() == B_OK) { + cache = attribute ? to->fAttrCache : to->fCache; + if (cache->Lock() == B_OK) { if (toChange.fAtomic - && to->fCache->ChangeInfo() == toChange.fBefore) { - to->fCache->AddEntry(toName, fileID, true); - to->fCache->SetChangeInfo(toChange.fAfter); + && cache->ChangeInfo() == toChange.fBefore) { + cache->AddEntry(toName, fileID, true); + cache->SetChangeInfo(toChange.fAfter); } else if (to->fCache->ChangeInfo() != toChange.fBefore) - to->fCache->Trash(); - to->fCache->Unlock(); + cache->Trash(); + cache->Unlock(); } - notify_entry_moved(from->fFileSystem->DevId(), from->ID(), fromName, - to->ID(), toName, FileIdToInoT(fileID)); + if (attribute) { + notify_attribute_changed(from->fFileSystem->DevId(), from->ID(), + fromName, B_ATTR_REMOVED); + notify_attribute_changed(to->fFileSystem->DevId(), to->ID(), toName, + B_ATTR_CREATED); + } else { + notify_entry_moved(from->fFileSystem->DevId(), from->ID(), fromName, + to->ID(), toName, FileIdToInoT(fileID)); + } return B_OK; } @@ -404,8 +436,11 @@ Inode::Access(int mode) status_t -Inode::Stat(struct stat* st) +Inode::Stat(struct stat* st, OpenAttrCookie* attr) { + if (attr != NULL) + return GetStat(st, attr); + status_t result = fMetaCache.GetStat(st); if (result != B_OK) { struct stat temp; @@ -421,11 +456,11 @@ Inode::Stat(struct stat* st) status_t -Inode::GetStat(struct stat* st) +Inode::GetStat(struct stat* st, OpenAttrCookie* attr) { AttrValue* values; uint32 count; - status_t result = NFS4Inode::GetStat(&values, &count); + status_t result = NFS4Inode::GetStat(&values, &count, attr); if (result != B_OK) return result; @@ -504,7 +539,7 @@ Inode::GetStat(struct stat* st) status_t -Inode::WriteStat(const struct stat* st, uint32 mask) +Inode::WriteStat(const struct stat* st, uint32 mask, OpenAttrCookie* cookie) { status_t result; AttrValue attr[6]; @@ -554,15 +589,18 @@ Inode::WriteStat(const struct stat* st, uint32 mask) i++; } - MutexLocker stateLocker(fStateLock); - result = NFS4Inode::WriteStat(fOpenState, attr, i); - stateLocker.Unlock(); + if (cookie == NULL) { + MutexLocker stateLocker(fStateLock); + result = NFS4Inode::WriteStat(fOpenState, attr, i); + stateLocker.Unlock(); - fMetaCache.InvalidateStat(); - if ((mask & B_STAT_MODE) != 0 || (mask & B_STAT_UID) != 0 - || (mask & B_STAT_GID) != 0) { - fMetaCache.InvalidateAccess(); - } + fMetaCache.InvalidateStat(); + if ((mask & B_STAT_MODE) != 0 || (mask & B_STAT_UID) != 0 + || (mask & B_STAT_GID) != 0) { + fMetaCache.InvalidateAccess(); + } + } else + result = NFS4Inode::WriteStat(cookie->fOpenState, attr, i); return result; } diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h b/src/add-ons/kernel/file_systems/nfs4/Inode.h index 62fffcff80..e5a477aa20 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -57,24 +57,33 @@ public: status_t Link(Inode* dir, const char* name); status_t Remove(const char* name, FileType type); static status_t Rename(Inode* from, Inode* to, - const char* fromName, const char* toName); + const char* fromName, const char* toName, + bool attribute = false); - status_t Stat(struct stat* st); - status_t WriteStat(const struct stat* st, uint32 mask); + status_t Stat(struct stat* st, + OpenAttrCookie* attr = NULL); + status_t WriteStat(const struct stat* st, uint32 mask, + OpenAttrCookie* attr = NULL); status_t Create(const char* name, int mode, int perms, OpenFileCookie* cookie, OpenDelegationData* data, ino_t* id); status_t Open(int mode, OpenFileCookie* cookie); status_t Close(OpenFileCookie* cookie); + + status_t OpenAttr(const char* name, int mode, + OpenAttrCookie* cookie, bool create, + int32 type = 0); + status_t CloseAttr(OpenAttrCookie* 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 ReadDirect(OpenFileCookie* cookie, off_t pos, + status_t ReadDirect(OpenStateCookie* cookie, off_t pos, void* buffer, size_t* length, bool* eof); - status_t WriteDirect(OpenFileCookie* cookie, off_t pos, + status_t WriteDirect(OpenStateCookie* cookie, off_t pos, const void* buffer, size_t *_length); status_t CreateDir(const char* name, int mode); @@ -96,6 +105,8 @@ public: _snapshot, OpenDirCookie* cookie, uint64* _change, bool attribute); + status_t LoadAttrDirHandle(); + protected: Inode(); @@ -115,7 +126,8 @@ protected: status_t ChildAdded(const char* name, uint64 fileID, const FileHandle& fileHandle); - status_t GetStat(struct stat* st); + status_t GetStat(struct stat* st, + OpenAttrCookie* attr = NULL); static inline status_t CheckLockType(short ltype, uint32 mode); diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp b/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp index ac80441cb7..f2c83fe6ab 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp @@ -55,6 +55,13 @@ Inode::OpenAttrDir(OpenDirCookie* cookie) cookie->fEOF = false; cookie->fAttrDir = true; + return LoadAttrDirHandle(); +} + + +status_t +Inode::LoadAttrDirHandle() +{ if (fInfo.fAttrDir.fSize == 0) { FileHandle handle; @@ -65,7 +72,7 @@ Inode::OpenAttrDir(OpenDirCookie* cookie) fInfo.fAttrDir = handle; } - return B_OK; + return B_OK; } diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp index 7bad21a6f5..2eb1a1b104 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp @@ -193,7 +193,72 @@ Inode::Close(OpenFileCookie* cookie) status_t -Inode::ReadDirect(OpenFileCookie* cookie, off_t pos, void* buffer, size_t* _length, +Inode::OpenAttr(const char* name, int mode, OpenAttrCookie* cookie, bool create, + int32 type) +{ + (void)type; + + status_t result = LoadAttrDirHandle(); + if (result != B_OK) + return result; + + OpenDelegationData data; + data.fType = OPEN_DELEGATE_NONE; + + OpenState* state = new OpenState; + if (state == NULL) + return B_NO_MEMORY; + + state->fInfo.fName = name; + state->fInfo.fParent = fInfo.fAttrDir; + result = NFS4Inode::OpenAttr(state, name, mode, &data, create); + if (result != B_OK) { + delete state; + return result; + } + + fFileSystem->AddOpenFile(state); + + cookie->fOpenState = state; + cookie->fFileSystem = fFileSystem; + cookie->fMode = mode; + + if (data.fType != OPEN_DELEGATE_NONE) { + Delegation* delegation + = new(std::nothrow) Delegation(data, this, fOpenState->fClientID, + true); + if (delegation != NULL) { + delegation->fInfo = state->fInfo; + delegation->fFileSystem = fFileSystem; + state->fDelegation = delegation; + fFileSystem->AddDelegation(delegation); + } + } + + if ((mode & O_TRUNC) == O_TRUNC) { + struct stat st; + st.st_size = 0; + WriteStat(&st, B_STAT_SIZE, cookie); + } + + return B_OK; +} + + +status_t +Inode::CloseAttr(OpenAttrCookie* cookie) +{ + cookie->fOpenState->fDelegation->GiveUp(); + fFileSystem->RemoveDelegation(cookie->fOpenState->fDelegation); + delete cookie->fOpenState->fDelegation; + delete cookie->fOpenState; + + return B_OK; +} + + +status_t +Inode::ReadDirect(OpenStateCookie* cookie, off_t pos, void* buffer, size_t* _length, bool* eof) { *eof = false; @@ -203,9 +268,10 @@ Inode::ReadDirect(OpenFileCookie* cookie, off_t pos, void* buffer, size_t* _leng *_length = min_c(ioSize, *_length); status_t result; + OpenState* state = cookie != NULL ? cookie->fOpenState : fOpenState; while (size < *_length && !*eof) { uint32 len = *_length - size; - result = ReadFile(cookie, fOpenState, pos + size, &len, + result = ReadFile(cookie, state, pos + size, &len, reinterpret_cast(buffer) + size, eof); if (result != B_OK) { if (size == 0) @@ -234,7 +300,7 @@ Inode::Read(OpenFileCookie* cookie, off_t pos, void* buffer, size_t* _length) status_t -Inode::WriteDirect(OpenFileCookie* cookie, off_t pos, const void* _buffer, +Inode::WriteDirect(OpenStateCookie* cookie, off_t pos, const void* _buffer, size_t *_length) { uint32 size = 0; @@ -243,12 +309,20 @@ Inode::WriteDirect(OpenFileCookie* cookie, off_t pos, const void* _buffer, uint32 ioSize = fFileSystem->Root()->IOSize(); *_length = min_c(ioSize, *_length); - fWriteDirty = true; + bool attribute = false; + OpenState* state = fOpenState; + if (cookie != NULL) { + attribute = cookie->fOpenState->fInfo.fHandle != fInfo.fHandle; + state = cookie->fOpenState; + } + + if (!attribute) + fWriteDirty = true; while (size < *_length) { uint32 len = *_length - size; - status_t result = WriteFile(cookie, fOpenState, pos + size, &len, - buffer + size); + status_t result = WriteFile(cookie, state, pos + size, + &len, buffer + size, attribute); if (result != B_OK) { if (size == 0) return result; diff --git a/src/add-ons/kernel/file_systems/nfs4/MetadataCache.cpp b/src/add-ons/kernel/file_systems/nfs4/MetadataCache.cpp index 901021c47a..d561e29424 100644 --- a/src/add-ons/kernel/file_systems/nfs4/MetadataCache.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/MetadataCache.cpp @@ -83,7 +83,10 @@ MetadataCache::GetAccess(uid_t uid, uint32* allowed) if (!it.HasCurrent()) return B_ENTRY_NOT_FOUND; - if (it.Current().fExpire < time(NULL)) { + if (!fForceValid) + it.Current().fForceValid = false; + + if (!it.Current().fForceValid && it.Current().fExpire < time(NULL)) { it.Remove(); return B_ERROR; } @@ -105,6 +108,7 @@ MetadataCache::SetAccess(uid_t uid, uint32 allowed) AccessEntry entry; entry.fAllowed = allowed; entry.fExpire = time(NULL) + kExpirationTime; + entry.fForceValid = fForceValid; fAccessCache.Insert(uid, entry); } diff --git a/src/add-ons/kernel/file_systems/nfs4/MetadataCache.h b/src/add-ons/kernel/file_systems/nfs4/MetadataCache.h index 26a5e971f1..07a13a3c58 100644 --- a/src/add-ons/kernel/file_systems/nfs4/MetadataCache.h +++ b/src/add-ons/kernel/file_systems/nfs4/MetadataCache.h @@ -20,6 +20,8 @@ class Inode; struct AccessEntry { time_t fExpire; + bool fForceValid; + uint32 fAllowed; }; diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp index a026e18d5c..9c0953221e 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp @@ -245,14 +245,17 @@ NFS4Inode::ReadLink(void* buffer, size_t* length) status_t -NFS4Inode::GetStat(AttrValue** values, uint32* count) +NFS4Inode::GetStat(AttrValue** values, uint32* count, OpenAttrCookie* cookie) { do { RPC::Server* serv = fFileSystem->Server(); Request request(serv); RequestBuilder& req = request.Builder(); - req.PutFH(fInfo.fHandle); + if (cookie != NULL) + req.PutFH(cookie->fOpenState->fInfo.fHandle); + else + req.PutFH(fInfo.fHandle); Attribute attr[] = { FATTR4_SIZE, FATTR4_MODE, FATTR4_NUMLINKS, FATTR4_OWNER, FATTR4_OWNER_GROUP, @@ -260,7 +263,7 @@ NFS4Inode::GetStat(AttrValue** values, uint32* count) FATTR4_TIME_METADATA, FATTR4_TIME_MODIFY }; req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); - status_t result = request.Send(); + status_t result = request.Send(cookie); if (result != B_OK) return result; @@ -284,7 +287,7 @@ NFS4Inode::WriteStat(OpenState* state, AttrValue* attrs, uint32 attrCount) Request request(serv); RequestBuilder& req = request.Builder(); - req.PutFH(fInfo.fHandle); + req.PutFH(state->fInfo.fHandle); if (state != NULL) req.SetAttr(state->fStateID, state->fStateSeq, attrs, attrCount); else @@ -313,21 +316,29 @@ NFS4Inode::WriteStat(OpenState* state, AttrValue* attrs, uint32 attrCount) status_t NFS4Inode::Rename(Inode* from, Inode* to, const char* fromName, const char* toName, ChangeInfo* fromChange, ChangeInfo* toChange, - uint64* fileID) + uint64* fileID, bool attribute) { do { RPC::Server* serv = from->fFileSystem->Server(); Request request(serv); RequestBuilder& req = request.Builder(); - req.PutFH(from->fInfo.fHandle); + if (attribute) + req.PutFH(from->fInfo.fAttrDir); + else + req.PutFH(from->fInfo.fHandle); req.SaveFH(); - req.PutFH(to->fInfo.fHandle); + if (attribute) + req.PutFH(to->fInfo.fAttrDir); + else + req.PutFH(to->fInfo.fHandle); req.Rename(fromName, toName); - Attribute attr[] = { FATTR4_FILEID }; - req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); - req.LookUp(toName); + if (!attribute) { + req.LookUp(toName); + Attribute attr[] = { FATTR4_FILEID }; + req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); + } status_t result = request.Send(); if (result != B_OK) @@ -358,22 +369,24 @@ NFS4Inode::Rename(Inode* from, Inode* to, const char* fromName, if (result != B_OK) return result; - result = reply.LookUp(); - if (result != B_OK) - return result; + if (!attribute) { + result = reply.LookUp(); + if (result != B_OK) + return result; - AttrValue* values; - uint32 count; - result = reply.GetAttr(&values, &count); - if (result != B_OK) - return result; + AttrValue* values; + uint32 count; + result = reply.GetAttr(&values, &count); + if (result != B_OK) + return result; - if (count == 0) - *fileID = from->fFileSystem->AllocFileId(); - else - *fileID = values[0].fData.fValue64; + if (count == 0) + *fileID = from->fFileSystem->AllocFileId(); + else + *fileID = values[0].fData.fValue64; - delete[] values; + delete[] values; + } return B_OK; } while (true); @@ -581,7 +594,61 @@ NFS4Inode::OpenFile(OpenState* state, int mode, OpenDelegationData* delegation) status_t -NFS4Inode::ReadFile(OpenFileCookie* cookie, OpenState* state, uint64 position, +NFS4Inode::OpenAttr(OpenState* state, const char* name, int mode, + OpenDelegationData* delegation, bool create) +{ + bool confirm; + status_t result; + uint32 sequence = fFileSystem->OpenOwnerSequenceLock(); + do { + state->fClientID = fFileSystem->NFSServer()->ClientId(); + + RPC::Server* serv = fFileSystem->Server(); + Request request(serv); + RequestBuilder& req = request.Builder(); + + req.PutFH(fInfo.fAttrDir); + req.Open(CLAIM_NULL, sequence, sModeToAccess(mode), state->fClientID, + create ? OPEN4_CREATE : OPEN4_NOCREATE, fFileSystem->OpenOwner(), + name); + req.GetFH(); + + result = request.Send(); + if (result != B_OK) { + fFileSystem->OpenOwnerSequenceUnlock(false); + return result; + } + + ReplyInterpreter& reply = request.Reply(); + + if (HandleErrors(reply.NFS4Error(), serv, NULL, state)) + continue; + + fFileSystem->OpenOwnerSequenceUnlock(); + + reply.PutFH(); + result = reply.Open(state->fStateID, &state->fStateSeq, &confirm, + delegation); + + reply.GetFH(&state->fInfo.fHandle); + + if (result != B_OK) + return result; + + break; + } while (true); + + state->fOpened = true; + + if (confirm) + return ConfirmOpen(fInfo.fHandle, state); + + return B_OK; +} + + +status_t +NFS4Inode::ReadFile(OpenStateCookie* cookie, OpenState* state, uint64 position, uint32* length, void* buffer, bool* eof) { do { @@ -589,7 +656,7 @@ NFS4Inode::ReadFile(OpenFileCookie* cookie, OpenState* state, uint64 position, Request request(serv); RequestBuilder& req = request.Builder(); - req.PutFH(fInfo.fHandle); + req.PutFH(state->fInfo.fHandle); req.Read(state->fStateID, state->fStateSeq, position, *length); status_t result = request.Send(cookie); @@ -612,8 +679,8 @@ NFS4Inode::ReadFile(OpenFileCookie* cookie, OpenState* state, uint64 position, status_t -NFS4Inode::WriteFile(OpenFileCookie* cookie, OpenState* state, uint64 position, - uint32* length, const void* buffer) +NFS4Inode::WriteFile(OpenStateCookie* cookie, OpenState* state, uint64 position, + uint32* length, const void* buffer, bool commit) { do { @@ -621,9 +688,10 @@ NFS4Inode::WriteFile(OpenFileCookie* cookie, OpenState* state, uint64 position, Request request(serv); RequestBuilder& req = request.Builder(); - req.PutFH(fInfo.fHandle); + req.PutFH(state->fInfo.fHandle); - req.Write(state->fStateID, state->fStateSeq, buffer, position, *length); + req.Write(state->fStateID, state->fStateSeq, buffer, position, *length, + commit); status_t result = request.Send(cookie); if (result != B_OK) @@ -757,8 +825,10 @@ NFS4Inode::RemoveObject(const char* name, FileType type, ChangeInfo* changeInfo, req.PutFH(fInfo.fHandle); - Attribute idAttr[] = { FATTR4_FILEID }; - req.GetAttr(idAttr, sizeof(idAttr) / sizeof(Attribute)); + if (type != NF4NAMEDATTR) { + Attribute idAttr[] = { FATTR4_FILEID }; + req.GetAttr(idAttr, sizeof(idAttr) / sizeof(Attribute)); + } req.Remove(name); @@ -790,17 +860,19 @@ NFS4Inode::RemoveObject(const char* name, FileType type, ChangeInfo* changeInfo, reply.PutFH(); - AttrValue* values; - uint32 count; - result = reply.GetAttr(&values, &count); - if (result != B_OK) - return result; + if (type != NF4NAMEDATTR) { + AttrValue* values; + uint32 count; + result = reply.GetAttr(&values, &count); + if (result != B_OK) + return result; - if (count == 0) - *fileID = fFileSystem->AllocFileId(); - else - *fileID = values[0].fData.fValue64; - delete[] values; + if (count == 0) + *fileID = fFileSystem->AllocFileId(); + else + *fileID = values[0].fData.fValue64; + delete[] values; + } return reply.Remove(&changeInfo->fBefore, &changeInfo->fAfter, changeInfo->fAtomic); diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h index fad2e89c53..110cce7ffe 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h @@ -38,9 +38,11 @@ protected: static status_t Rename(Inode* from, Inode* to, const char* fromName, const char* toName, ChangeInfo* fromChange, - ChangeInfo* toChange, uint64* fileID); + ChangeInfo* toChange, uint64* fileID, + bool attribute = false); - status_t GetStat(AttrValue** values, uint32* count); + status_t GetStat(AttrValue** values, uint32* count, + OpenAttrCookie* attr = NULL); status_t WriteStat(OpenState* state, AttrValue* attrs, uint32 attrCount); @@ -51,12 +53,15 @@ protected: status_t OpenFile(OpenState* state, int mode, OpenDelegationData* delegation); - status_t ReadFile(OpenFileCookie* cookie, OpenState* state, + status_t OpenAttr(OpenState* state, const char* name, int mode, + OpenDelegationData* delegation, bool create); + + status_t ReadFile(OpenStateCookie* cookie, OpenState* state, uint64 position, uint32* length, void* buffer, bool* eof); - status_t WriteFile(OpenFileCookie* cookie, OpenState* state, + status_t WriteFile(OpenStateCookie* cookie, OpenState* state, uint64 position, uint32* length, - const void* buffer); + const void* buffer, bool commit = false); status_t CreateObject(const char* name, const char* path, int mode, FileType type, ChangeInfo* changeInfo, diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp index 192e691f00..6663cc30ad 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp @@ -16,7 +16,7 @@ bool NFS4Object::HandleErrors(uint32 nfs4Error, RPC::Server* serv, - OpenFileCookie* cookie, OpenState* state) + OpenStateCookie* cookie, OpenState* state) { uint32 leaseTime; diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Object.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Object.h index 79df6f1337..3af5129144 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Object.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Object.h @@ -13,13 +13,13 @@ #include "RPCServer.h" -class OpenFileCookie; +class OpenStateCookie; class OpenState; class NFS4Object { public: bool HandleErrors(uint32 nfs4Error, RPC::Server* serv, - OpenFileCookie* cookie = NULL, OpenState* state = NULL); + OpenStateCookie* cookie = NULL, OpenState* state = NULL); status_t ConfirmOpen(const FileHandle& fileHandle, OpenState* state); diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp index 04add4c0e4..3eab8254b7 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp @@ -788,7 +788,7 @@ RequestBuilder::Verify(AttrValue* attr, uint32 count) status_t RequestBuilder::Write(const uint32* id, uint32 stateSeq, const void* buffer, - uint64 pos, uint32 len) + uint64 pos, uint32 len, bool stable) { if (fProcedure != ProcCompound) return B_BAD_VALUE; @@ -801,7 +801,7 @@ RequestBuilder::Write(const uint32* id, uint32 stateSeq, const void* buffer, fRequest->Stream().AddUInt(id[1]); fRequest->Stream().AddUInt(id[2]); fRequest->Stream().AddUHyper(pos); - fRequest->Stream().AddInt(UNSTABLE4); + fRequest->Stream().AddInt(stable ? FILE_SYNC4 : UNSTABLE4); fRequest->Stream().AddOpaque(buffer, len); fOpCount++; @@ -862,6 +862,12 @@ void RequestBuilder::_EncodeAttrs(XDR::WriteStream& stream, AttrValue* attr, uint32 count) { + if (count == 0) { + stream.AddUInt(0); + stream.AddOpaque(NULL, 0); + return; + } + Attribute* attrs = reinterpret_cast(malloc(sizeof(Attribute) * count)); for (uint32 i = 0; i < count; i++) diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h index 9ef417413b..1b0ea90dc3 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h @@ -78,7 +78,7 @@ public: status_t Verify(AttrValue* attr, uint32 count); status_t Write(const uint32* id, uint32 stateSeq, const void* buffer, uint64 pos, - uint32 len); + uint32 len, bool stable = false); status_t ReleaseLockOwner(OpenState* state, LockOwner* owner); 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 17e1d7c8f5..e2483320c0 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -636,7 +636,7 @@ nfs4_open_attr_dir(fs_volume* volume, fs_vnode* vnode, void** _cookie) static status_t nfs4_close_attr_dir(fs_volume* volume, fs_vnode* vnode, void* cookie) { - return nfs4_close_attr_dir(volume, vnode, cookie); + return nfs4_close_dir(volume, vnode, cookie); } @@ -658,7 +658,125 @@ nfs4_read_attr_dir(fs_volume* volume, fs_vnode* vnode, void* cookie, static status_t nfs4_rewind_attr_dir(fs_volume* volume, fs_vnode* vnode, void* cookie) { - return nfs4_rewind_attr_dir(volume, vnode, cookie); + return nfs4_rewind_dir(volume, vnode, cookie); +} + + +static status_t +nfs4_create_attr(fs_volume* volume, fs_vnode* vnode, const char* name, + uint32 type, int openMode, void** _cookie) +{ + Inode* inode = reinterpret_cast(vnode->private_node); + + OpenAttrCookie* cookie = new OpenAttrCookie; + if (cookie == NULL) + return B_NO_MEMORY; + *_cookie = cookie; + + status_t result = inode->OpenAttr(name, openMode, cookie, true, type); + if (result != B_OK) + delete cookie; + + return result; +} + + +static status_t +nfs4_open_attr(fs_volume* volume, fs_vnode* vnode, const char* name, + int openMode, void** _cookie) +{ + Inode* inode = reinterpret_cast(vnode->private_node); + + OpenAttrCookie* cookie = new OpenAttrCookie; + if (cookie == NULL) + return B_NO_MEMORY; + *_cookie = cookie; + + status_t result = inode->OpenAttr(name, openMode, cookie, false); + if (result != B_OK) + delete cookie; + + return result; +} + + +static status_t +nfs4_close_attr(fs_volume* volume, fs_vnode* vnode, void* _cookie) +{ + Cookie* cookie = reinterpret_cast(_cookie); + return cookie->CancelAll(); +} + + +static status_t +nfs4_free_attr_cookie(fs_volume* volume, fs_vnode* vnode, void* _cookie) +{ + Inode* inode = reinterpret_cast(vnode->private_node); + + OpenAttrCookie* cookie = reinterpret_cast(_cookie); + inode->CloseAttr(cookie); + delete cookie; + + return B_OK; +} + + +static status_t +nfs4_read_attr(fs_volume* volume, fs_vnode* vnode, void* _cookie, off_t pos, + void* buffer, size_t* length) +{ + Inode* inode = reinterpret_cast(vnode->private_node); + OpenAttrCookie* cookie = reinterpret_cast(_cookie); + bool eof; + return inode->ReadDirect(cookie, pos, buffer, length, &eof); +} + + +static status_t +nfs4_write_attr(fs_volume* volume, fs_vnode* vnode, void* _cookie, off_t pos, + const void* buffer, size_t* length) +{ + Inode* inode = reinterpret_cast(vnode->private_node); + OpenAttrCookie* cookie = reinterpret_cast(_cookie); + return inode->WriteDirect(cookie, pos, buffer, length); +} + + +static status_t +nfs4_read_attr_stat(fs_volume* volume, fs_vnode* vnode, void* _cookie, + struct stat* stat) +{ + Inode* inode = reinterpret_cast(vnode->private_node); + OpenAttrCookie* cookie = reinterpret_cast(_cookie); + return inode->Stat(stat, cookie); +} + + +static status_t +nfs4_write_attr_stat(fs_volume* volume, fs_vnode* vnode, void* _cookie, + const struct stat* stat, int statMask) +{ + Inode* inode = reinterpret_cast(vnode->private_node); + OpenAttrCookie* cookie = reinterpret_cast(_cookie); + return inode->WriteStat(stat, statMask, cookie); +} + + +static status_t +nfs4_rename_attr(fs_volume* volume, fs_vnode* fromVnode, const char* fromName, + fs_vnode* toVnode, const char* toName) +{ + Inode* fromInode = reinterpret_cast(fromVnode->private_node); + Inode* toInode = reinterpret_cast(toVnode->private_node); + return Inode::Rename(fromInode, toInode, fromName, toName, true); +} + + +static status_t +nfs4_remove_attr(fs_volume* volume, fs_vnode* vnode, const char* name) +{ + Inode* inode = reinterpret_cast(vnode->private_node); + return inode->Remove(name, NF4NAMEDATTR); } @@ -832,17 +950,17 @@ fs_vnode_ops gNFSv4VnodeOps = { nfs4_rewind_attr_dir, /* attribute operations */ - NULL, // create_attr - NULL, // open_attr - NULL, // close_attr - NULL, // free_attr_cookie - NULL, // read_attr - NULL, // write_attr + nfs4_create_attr, + nfs4_open_attr, + nfs4_close_attr, + nfs4_free_attr_cookie, + nfs4_read_attr, + nfs4_write_attr, - NULL, // read_attr_stat - NULL, // write_attr_stat - NULL, // rename_attr - NULL, // remove_attr + nfs4_read_attr_stat, + nfs4_write_attr_stat, + nfs4_rename_attr, + nfs4_remove_attr, /* support for node and FS layers */ NULL, // create_special_node From 775a18c15539d65febd73c7f9858fb118bb6faff Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Thu, 9 Aug 2012 23:54:22 +0200 Subject: [PATCH 182/252] nfs4: Fix WriteState when state == NULL --- src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp index 9c0953221e..565b5020ac 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp @@ -287,11 +287,13 @@ NFS4Inode::WriteStat(OpenState* state, AttrValue* attrs, uint32 attrCount) Request request(serv); RequestBuilder& req = request.Builder(); - req.PutFH(state->fInfo.fHandle); - if (state != NULL) + if (state != NULL) { + req.PutFH(state->fInfo.fHandle); req.SetAttr(state->fStateID, state->fStateSeq, attrs, attrCount); - else + } else { + req.PutFH(fInfo.fHandle); req.SetAttr(NULL, 0, attrs, attrCount); + } status_t result = request.Send(); if (result != B_OK) From ad5adda8e7a704244a13beec503c41d16854e0ab Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Thu, 9 Aug 2012 23:57:31 +0200 Subject: [PATCH 183/252] nfs4: Fix assignment to temporary --- src/add-ons/kernel/file_systems/nfs4/MetadataCache.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/MetadataCache.cpp b/src/add-ons/kernel/file_systems/nfs4/MetadataCache.cpp index d561e29424..6429e6e9b4 100644 --- a/src/add-ons/kernel/file_systems/nfs4/MetadataCache.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/MetadataCache.cpp @@ -84,7 +84,7 @@ MetadataCache::GetAccess(uid_t uid, uint32* allowed) return B_ENTRY_NOT_FOUND; if (!fForceValid) - it.Current().fForceValid = false; + it.CurrentValuePointer()->fForceValid = false; if (!it.Current().fForceValid && it.Current().fExpire < time(NULL)) { it.Remove(); @@ -167,3 +167,4 @@ MetadataCache::NotifyChanges(const struct stat* oldStat, notify_stat_changed(fInode->GetFileSystem()->DevId(), fInode->ID(), flags); } + From 1fdcaccf17782c690dc056f8655e68ccdb85e8c1 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Fri, 10 Aug 2012 00:01:15 +0200 Subject: [PATCH 184/252] AVLTreeMap::MakeEmpty should set fTree.fRoot to NULL --- headers/private/kernel/util/AVLTreeMap.h | 1 + 1 file changed, 1 insertion(+) diff --git a/headers/private/kernel/util/AVLTreeMap.h b/headers/private/kernel/util/AVLTreeMap.h index ea436be3c1..051f4e7fdd 100644 --- a/headers/private/kernel/util/AVLTreeMap.h +++ b/headers/private/kernel/util/AVLTreeMap.h @@ -269,6 +269,7 @@ _AVL_TREE_MAP_CLASS_NAME::MakeEmpty() { AVLTreeNode* root = fTree.Root(); _FreeTree(root); + fTree.MakeEmpty(); } From 0e0d53c7995f23e83364ec628c9623041e2b22bc Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Fri, 10 Aug 2012 00:18:37 +0200 Subject: [PATCH 185/252] nfs4: Fill struct stat st_blksize and st_blocks fields --- src/add-ons/kernel/file_systems/nfs4/Inode.cpp | 4 ++++ src/add-ons/kernel/file_systems/nfs4/MetadataCache.cpp | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index b0af3541b3..cd7f14b3d6 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -534,6 +534,10 @@ Inode::GetStat(struct stat* st, OpenAttrCookie* attr) memset(&st->st_mtim, 0, sizeof(timespec)); delete[] values; + st->st_blksize = fFileSystem->Root()->IOSize(); + st->st_blocks = st->st_size / st->st_blksize; + st->st_blocks += st->st_size % st->st_blksize == 0 ? 0 : 1; + return B_OK; } diff --git a/src/add-ons/kernel/file_systems/nfs4/MetadataCache.cpp b/src/add-ons/kernel/file_systems/nfs4/MetadataCache.cpp index 6429e6e9b4..3c0f9b6008 100644 --- a/src/add-ons/kernel/file_systems/nfs4/MetadataCache.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/MetadataCache.cpp @@ -46,7 +46,8 @@ MetadataCache::GetStat(struct stat* st) st->st_ctim = fStatCache.st_ctim; st->st_crtim = fStatCache.st_crtim; st->st_mtim = fStatCache.st_mtim; - + st->st_blksize = fStatCache.st_blksize; + st->st_blocks = fStatCache.st_blocks; return B_OK; } From b1fd656d454ab89fbfdac09fda1b6aafd81bbe89 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Fri, 10 Aug 2012 02:34:41 +0200 Subject: [PATCH 186/252] nfs4: Fix server reboot recovery --- .../kernel/file_systems/nfs4/Delegation.cpp | 2 +- .../kernel/file_systems/nfs4/Delegation.h | 8 +++++ .../kernel/file_systems/nfs4/FileSystem.cpp | 22 +++---------- .../kernel/file_systems/nfs4/FileSystem.h | 4 +-- .../kernel/file_systems/nfs4/Inode.cpp | 8 ++--- src/add-ons/kernel/file_systems/nfs4/Inode.h | 9 +++++ .../kernel/file_systems/nfs4/InodeRegular.cpp | 1 - .../kernel/file_systems/nfs4/NFS4Inode.cpp | 2 +- .../kernel/file_systems/nfs4/NFS4Object.cpp | 9 ++++- .../kernel/file_systems/nfs4/NFS4Object.h | 3 +- .../kernel/file_systems/nfs4/NFS4Server.cpp | 6 ++-- .../kernel/file_systems/nfs4/OpenState.cpp | 33 +++++++++++++++---- .../kernel/file_systems/nfs4/OpenState.h | 6 ++-- .../file_systems/nfs4/ReplyInterpreter.cpp | 1 + 14 files changed, 73 insertions(+), 41 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Delegation.cpp b/src/add-ons/kernel/file_systems/nfs4/Delegation.cpp index 19ea2f2a63..a0ce499edb 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Delegation.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Delegation.cpp @@ -53,7 +53,7 @@ Delegation::ReturnDelegation() ReplyInterpreter& reply = request.Reply(); - if (HandleErrors(reply.NFS4Error(), serv)) + if (HandleErrors(reply.NFS4Error(), serv, NULL, fInode->GetOpenState())) continue; reply.PutFH(); diff --git a/src/add-ons/kernel/file_systems/nfs4/Delegation.h b/src/add-ons/kernel/file_systems/nfs4/Delegation.h index f901173d23..807d52617c 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Delegation.h +++ b/src/add-ons/kernel/file_systems/nfs4/Delegation.h @@ -25,6 +25,7 @@ public: status_t GiveUp(bool truncate = false); + inline void SetData(const OpenDelegationData& data); inline Inode* GetInode(); inline OpenDelegation Type(); @@ -39,6 +40,13 @@ private: }; +inline void +Delegation::SetData(const OpenDelegationData& data) +{ + fData = data; +} + + inline Inode* Delegation::GetInode() { diff --git a/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp b/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp index ecc56b28db..d211299d9e 100644 --- a/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp @@ -25,7 +25,6 @@ FileSystem::FileSystem() : fNext(NULL), fPrev(NULL), - fOpenFiles(NULL), fOpenCount(0), fOpenOwnerSequence(0), fPath(NULL), @@ -267,7 +266,7 @@ FileSystem::Migrate(const RPC::Server* serv) } -OpenState* +DoublyLinkedList& FileSystem::OpenFilesLock() { mutex_lock(&fOpenLock); @@ -287,11 +286,8 @@ FileSystem::AddOpenFile(OpenState* state) { MutexLocker _(fOpenLock); - state->fPrev = NULL; - state->fNext = fOpenFiles; - if (fOpenFiles != NULL) - fOpenFiles->fPrev = state; - fOpenFiles = state; + fOpenFiles.InsertBefore(fOpenFiles.Head(), state); + NFSServer()->IncUsage(); } @@ -300,13 +296,9 @@ void FileSystem::RemoveOpenFile(OpenState* state) { MutexLocker _(fOpenLock); - if (state == fOpenFiles) - fOpenFiles = state->fNext; - if (state->fNext) - state->fNext->fPrev = state->fPrev; - if (state->fPrev) - state->fPrev->fNext = state->fNext; + fOpenFiles.Remove(state); + NFSServer()->DecUsage(); } @@ -335,8 +327,6 @@ FileSystem::AddDelegation(Delegation* delegation) fHandleToDelegation.Remove(delegation->fInfo.fHandle); fHandleToDelegation.Insert(delegation->fInfo.fHandle, delegation); - - NFSServer()->IncUsage(); } @@ -347,8 +337,6 @@ FileSystem::RemoveDelegation(Delegation* delegation) fDelegationList.Remove(delegation); fHandleToDelegation.Remove(delegation->fInfo.fHandle); - - NFSServer()->DecUsage(); } diff --git a/src/add-ons/kernel/file_systems/nfs4/FileSystem.h b/src/add-ons/kernel/file_systems/nfs4/FileSystem.h index adfea0a294..b055e3bc7e 100644 --- a/src/add-ons/kernel/file_systems/nfs4/FileSystem.h +++ b/src/add-ons/kernel/file_systems/nfs4/FileSystem.h @@ -30,7 +30,7 @@ public: status_t Migrate(const RPC::Server* serv); - OpenState* OpenFilesLock(); + DoublyLinkedList& OpenFilesLock(); void OpenFilesUnlock(); inline uint32 OpenFilesCount(); void AddOpenFile(OpenState* state); @@ -73,7 +73,7 @@ private: DoublyLinkedList fDelegationList; AVLTreeMap fHandleToDelegation; - OpenState* fOpenFiles; + DoublyLinkedList fOpenFiles; uint32 fOpenCount; mutex fOpenLock; diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index cd7f14b3d6..02ea63e224 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -857,9 +857,9 @@ Inode::RecallReadDelegation() void Inode::ReturnDelegation(bool truncate) { - fMetaCache.UnlockValid(); - fDelegation->GiveUp(truncate); + + fMetaCache.UnlockValid(); fFileSystem->RemoveDelegation(fDelegation); MutexLocker stateLocker(fStateLock); @@ -874,10 +874,8 @@ Inode::ReturnDelegation(bool truncate) void Inode::ReleaseOpenState() { - if (fOpenState->ReleaseReference() == 1) { - fFileSystem->RemoveOpenFile(fOpenState); + if (fOpenState->ReleaseReference() == 1) fOpenState = NULL; - } } diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h b/src/add-ons/kernel/file_systems/nfs4/Inode.h index e5a477aa20..ab8feecec4 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -37,6 +37,8 @@ public: inline uint64 Change(); inline bool Dirty(); + inline OpenState* GetOpenState(); + void SetDelegation(Delegation* delegation); void RecallDelegation(bool truncate = false); void RecallReadDelegation(); @@ -230,5 +232,12 @@ Inode::Dirty() } +inline OpenState* +Inode::GetOpenState() +{ + return fOpenState; +} + + #endif // INODE_H diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp index 2eb1a1b104..5490ee0582 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp @@ -252,7 +252,6 @@ Inode::CloseAttr(OpenAttrCookie* cookie) fFileSystem->RemoveDelegation(cookie->fOpenState->fDelegation); delete cookie->fOpenState->fDelegation; delete cookie->fOpenState; - return B_OK; } diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp index 565b5020ac..4f4dc738cd 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp @@ -553,7 +553,7 @@ NFS4Inode::OpenFile(OpenState* state, int mode, OpenDelegationData* delegation) ReplyInterpreter& reply = request.Reply(); - if (HandleErrors(reply.NFS4Error(), serv, NULL, state)) + if (HandleErrors(reply.NFS4Error(), serv, NULL, state, &sequence)) continue; fFileSystem->OpenOwnerSequenceUnlock(); diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp index 6663cc30ad..fc5aecfb3e 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp @@ -16,7 +16,7 @@ bool NFS4Object::HandleErrors(uint32 nfs4Error, RPC::Server* serv, - OpenStateCookie* cookie, OpenState* state) + OpenStateCookie* cookie, OpenState* state, uint32* sequence) { uint32 leaseTime; @@ -67,7 +67,14 @@ NFS4Object::HandleErrors(uint32 nfs4Error, RPC::Server* serv, case NFS4ERR_STALE_CLIENTID: case NFS4ERR_STALE_STATEID: if (state != NULL) { + if (sequence != NULL) + fFileSystem->OpenOwnerSequenceUnlock(false); + fFileSystem->NFSServer()->ServerRebooted(state->fClientID); +dprintf("returned rebooted\n"); + if (sequence != NULL) + *sequence = fFileSystem->OpenOwnerSequenceLock(); +dprintf("locked again\n"); return true; } return false; diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Object.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Object.h index 3af5129144..817b1c2c65 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Object.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Object.h @@ -19,7 +19,8 @@ class OpenState; class NFS4Object { public: bool HandleErrors(uint32 nfs4Error, RPC::Server* serv, - OpenStateCookie* cookie = NULL, OpenState* state = NULL); + OpenStateCookie* cookie = NULL, OpenState* state = NULL, + uint32* sequence = NULL); status_t ConfirmOpen(const FileHandle& fileHandle, OpenState* state); diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp index 07acb75e53..173e527596 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp @@ -58,11 +58,13 @@ NFS4Server::ServerRebooted(uint64 clientId) MutexLocker _(fFSLock); FileSystem* fs = fFileSystems; while (fs != NULL) { - OpenState* current = fs->OpenFilesLock(); + DoublyLinkedList::Iterator iterator + = fs->OpenFilesLock().GetIterator(); + OpenState* current = iterator.Next(); while (current != NULL) { current->Reclaim(fClientId); - current = current->fNext; + current = iterator.Next(); } fs->OpenFilesUnlock(); diff --git a/src/add-ons/kernel/file_systems/nfs4/OpenState.cpp b/src/add-ons/kernel/file_systems/nfs4/OpenState.cpp index 388b62fc8e..62c93bba02 100644 --- a/src/add-ons/kernel/file_systems/nfs4/OpenState.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/OpenState.cpp @@ -13,6 +13,7 @@ #include "FileSystem.h" #include "Request.h" +#include "WorkQueue.h" OpenState::OpenState() @@ -31,7 +32,9 @@ OpenState::OpenState() OpenState::~OpenState() { + fFileSystem->RemoveOpenFile(this); Close(); + mutex_destroy(&fLock); mutex_destroy(&fLocksLock); @@ -140,9 +143,10 @@ OpenState::Reclaim(uint64 newClientID) if (fClientID == newClientID) return B_OK; fClientID = newClientID; - +dprintf("reclaim start\n"); _ReclaimOpen(newClientID); _ReclaimLocks(newClientID); +dprintf("reclaim end\n"); return B_OK; } @@ -150,10 +154,16 @@ OpenState::Reclaim(uint64 newClientID) status_t OpenState::_ReclaimOpen(uint64 newClientID) { + dprintf("reclaim %s\n", fInfo.fName); + bool confirm; OpenDelegationData delegation; + delegation.fType = OPEN_DELEGATE_NONE; + delegation.fRecall = false; uint32 sequence = fFileSystem->OpenOwnerSequenceLock(); + OpenDelegation delegType = fDelegation != NULL ? fDelegation->Type() + : OPEN_DELEGATE_NONE; do { RPC::Server* server = fFileSystem->Server(); Request request(server); @@ -162,7 +172,7 @@ OpenState::_ReclaimOpen(uint64 newClientID) req.PutFH(fInfo.fHandle); req.Open(CLAIM_PREVIOUS, sequence, sModeToAccess(fMode), newClientID, OPEN4_NOCREATE, fFileSystem->OpenOwner(), NULL, NULL, 0, false, - fDelegation->Type()); + delegType); status_t result = request.Send(); if (result != B_OK) { @@ -172,7 +182,7 @@ OpenState::_ReclaimOpen(uint64 newClientID) ReplyInterpreter& reply = request.Reply(); - if (HandleErrors(reply.NFS4Error(), server)) + if (HandleErrors(reply.NFS4Error(), server, NULL, NULL, &sequence)) continue; fFileSystem->OpenOwnerSequenceUnlock(); @@ -182,10 +192,19 @@ OpenState::_ReclaimOpen(uint64 newClientID) result = reply.Open(fStateID, &fStateSeq, &confirm, &delegation); if (result != B_OK) return result; + + break; } while (true); - if (delegation.fRecall) - fDelegation->GiveUp(); + if (fDelegation != NULL) + fDelegation->SetData(delegation); + + if (delegation.fRecall) { + DelegationRecallArgs* args = new(std::nothrow) DelegationRecallArgs; + args->fDelegation = fDelegation; + args->fTruncate = false; + gWorkQueue->EnqueueJob(DelegationRecall, args); + } if (confirm) return ConfirmOpen(fInfo.fHandle, this); @@ -197,6 +216,8 @@ OpenState::_ReclaimOpen(uint64 newClientID) status_t OpenState::_ReclaimLocks(uint64 newClientID) { + dprintf("reclaim locks %s\n", fInfo.fName); + MutexLocker _(fLocksLock); LockInfo* linfo = fLocks; while (linfo != NULL) { @@ -264,7 +285,7 @@ OpenState::Close() ReplyInterpreter& reply = request.Reply(); - if (HandleErrors(reply.NFS4Error(), serv, NULL, this)) + if (HandleErrors(reply.NFS4Error(), serv, NULL, this, &sequence)) continue; fFileSystem->OpenOwnerSequenceUnlock(); diff --git a/src/add-ons/kernel/file_systems/nfs4/OpenState.h b/src/add-ons/kernel/file_systems/nfs4/OpenState.h index 8cfdce5253..f810528903 100644 --- a/src/add-ons/kernel/file_systems/nfs4/OpenState.h +++ b/src/add-ons/kernel/file_systems/nfs4/OpenState.h @@ -17,7 +17,8 @@ #include "NFS4Object.h" -struct OpenState : public NFS4Object, public KernelReferenceable { +struct OpenState : public NFS4Object, public KernelReferenceable, + public DoublyLinkedListLinkImpl { OpenState(); ~OpenState(); @@ -38,9 +39,6 @@ struct OpenState : public NFS4Object, public KernelReferenceable { LockOwner* fLockOwners; mutex fOwnerLock; - OpenState* fNext; - OpenState* fPrev; - LockOwner* GetLockOwner(uint32 owner); void AddLock(LockInfo* lock); diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp index b26082d78f..581282753c 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp @@ -827,6 +827,7 @@ ReplyInterpreter::_NFS4ErrorToHaiku(uint32 x) case NFS4ERR_ISDIR: return B_IS_A_DIRECTORY; case NFS4ERR_INVAL: return B_BAD_VALUE; case NFS4ERR_FBIG: return B_FILE_TOO_LARGE; + case NFS4ERR_NOTSUPP: return B_UNSUPPORTED; // ... case NFS4ERR_DELAY: case NFS4ERR_DENIED: From 7f504091ecf0cec2316b9c5fa079836d56130624 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Fri, 10 Aug 2012 02:56:44 +0200 Subject: [PATCH 187/252] nfs4: Fix directory cache revalidation when cache invalid --- src/add-ons/kernel/file_systems/nfs4/DirectoryCache.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.cpp b/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.cpp index 909f62956a..e7062c0567 100644 --- a/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.cpp @@ -185,6 +185,11 @@ DirectoryCache::Revalidate() } DirectoryCacheSnapshot* oldSnapshot = fDirectoryCache; + if (oldSnapshot == NULL) { + Trash(); + return B_ERROR; + } + oldSnapshot->AcquireReference(); Trash(); @@ -194,7 +199,7 @@ DirectoryCache::Revalidate() fAttrDir); if (result != B_OK) { oldSnapshot->ReleaseReference(); - return B_OK; + return B_ERROR; } newSnapshot->AcquireReference(); From b6d5fa9204f9e7e12f557544770d7040382664e1 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Tue, 14 Aug 2012 04:06:38 +0200 Subject: [PATCH 188/252] nfs4: Make sure that request are properly sequenced --- .../kernel/file_systems/nfs4/FileSystem.h | 7 +- .../kernel/file_systems/nfs4/NFS4Inode.cpp | 70 ++++++++++++------- .../kernel/file_systems/nfs4/NFS4Object.cpp | 66 +++++++++++++---- .../kernel/file_systems/nfs4/NFS4Object.h | 15 ++-- .../kernel/file_systems/nfs4/OpenState.cpp | 32 +++++---- 5 files changed, 124 insertions(+), 66 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/FileSystem.h b/src/add-ons/kernel/file_systems/nfs4/FileSystem.h index b055e3bc7e..10850e96b2 100644 --- a/src/add-ons/kernel/file_systems/nfs4/FileSystem.h +++ b/src/add-ons/kernel/file_systems/nfs4/FileSystem.h @@ -60,7 +60,7 @@ public: inline uint64 OpenOwner() const; inline uint32 OpenOwnerSequenceLock(); - inline void OpenOwnerSequenceUnlock(bool increment = true); + inline void OpenOwnerSequenceUnlock(uint32 sequence); FileSystem* fNext; FileSystem* fPrev; @@ -198,10 +198,9 @@ FileSystem::OpenOwnerSequenceLock() inline void -FileSystem::OpenOwnerSequenceUnlock(bool increment = true) +FileSystem::OpenOwnerSequenceUnlock(uint32 sequence) { - if (increment) - fOpenOwnerSequence++; + fOpenOwnerSequence = sequence; mutex_unlock(&fOpenOwnerLock); } diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp index 4f4dc738cd..79a79d8189 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp @@ -454,30 +454,29 @@ NFS4Inode::CreateFile(const char* name, int mode, int perms, OpenState* state, result = request.Send(); if (result != B_OK) { - fFileSystem->OpenOwnerSequenceUnlock(false); + fFileSystem->OpenOwnerSequenceUnlock(sequence); return result; } ReplyInterpreter& reply = request.Reply(); - if (reply.NFS4Error() == NFS4ERR_BADOWNER) { - fFileSystem->OpenOwnerSequenceUnlock(); - sequence = fFileSystem->OpenOwnerSequenceLock(); + sequence += IncrementSequence(reply.NFS4Error()); + if (reply.NFS4Error() == NFS4ERR_BADOWNER) { badOwner = true; continue; } - if (HandleErrors(reply.NFS4Error(), serv)) + if (HandleErrors(reply.NFS4Error(), serv, NULL, state, &sequence)) continue; - fFileSystem->OpenOwnerSequenceUnlock(); - reply.PutFH(); result = reply.Open(state->fStateID, &state->fStateSeq, &confirm, delegation, changeInfo); - if (result != B_OK) + if (result != B_OK) { + fFileSystem->OpenOwnerSequenceUnlock(sequence); return result; + } reply.GetFH(handle); @@ -485,8 +484,10 @@ NFS4Inode::CreateFile(const char* name, int mode, int perms, OpenState* state, AttrValue* values; uint32 count; result = reply.GetAttr(&values, &count); - if (result != B_OK) + if (result != B_OK) { + fFileSystem->OpenOwnerSequenceUnlock(sequence); return result; + } *fileID = values[0].fData.fValue64; @@ -500,9 +501,10 @@ NFS4Inode::CreateFile(const char* name, int mode, int perms, OpenState* state, state->fOpened = true; if (confirm) - return ConfirmOpen(*handle, state); + result = ConfirmOpen(*handle, state, &sequence); - return B_OK; + fFileSystem->OpenOwnerSequenceUnlock(sequence); + return result; } @@ -547,7 +549,7 @@ NFS4Inode::OpenFile(OpenState* state, int mode, OpenDelegationData* delegation) result = request.Send(); if (result != B_OK) { - fFileSystem->OpenOwnerSequenceUnlock(false); + fFileSystem->OpenOwnerSequenceUnlock(sequence); return result; } @@ -556,7 +558,7 @@ NFS4Inode::OpenFile(OpenState* state, int mode, OpenDelegationData* delegation) if (HandleErrors(reply.NFS4Error(), serv, NULL, state, &sequence)) continue; - fFileSystem->OpenOwnerSequenceUnlock(); + sequence += IncrementSequence(reply.NFS4Error()); // Verify if the file we want to open is the file this Inode // represents. @@ -564,9 +566,17 @@ NFS4Inode::OpenFile(OpenState* state, int mode, OpenDelegationData* delegation) fFileSystem->ExpireType() == FH4_PERSISTENT) { reply.PutFH(); result = reply.LookUp(); - if (result != B_OK) + if (result != B_OK) { + fFileSystem->OpenOwnerSequenceUnlock(sequence); return result; + } + result = reply.Verify(); + if (result != B_OK) { + fFileSystem->OpenOwnerSequenceUnlock(sequence); + return result; + } + if (result != B_OK && reply.NFS4Error() == NFS4ERR_NOT_SAME) return B_ENTRY_NOT_FOUND; else if (result != B_OK) @@ -580,8 +590,10 @@ NFS4Inode::OpenFile(OpenState* state, int mode, OpenDelegationData* delegation) FileHandle handle; reply.GetFH(&handle); - if (result != B_OK) + if (result != B_OK) { + fFileSystem->OpenOwnerSequenceUnlock(sequence); return result; + } break; } while (true); @@ -589,9 +601,10 @@ NFS4Inode::OpenFile(OpenState* state, int mode, OpenDelegationData* delegation) state->fOpened = true; if (confirm) - return ConfirmOpen(fInfo.fHandle, state); + result = ConfirmOpen(fInfo.fHandle, state, &sequence); - return B_OK; + fFileSystem->OpenOwnerSequenceUnlock(sequence); + return result; } @@ -617,7 +630,7 @@ NFS4Inode::OpenAttr(OpenState* state, const char* name, int mode, result = request.Send(); if (result != B_OK) { - fFileSystem->OpenOwnerSequenceUnlock(false); + fFileSystem->OpenOwnerSequenceUnlock(sequence); return result; } @@ -626,7 +639,7 @@ NFS4Inode::OpenAttr(OpenState* state, const char* name, int mode, if (HandleErrors(reply.NFS4Error(), serv, NULL, state)) continue; - fFileSystem->OpenOwnerSequenceUnlock(); + sequence += IncrementSequence(reply.NFS4Error()); reply.PutFH(); result = reply.Open(state->fStateID, &state->fStateSeq, &confirm, @@ -634,8 +647,10 @@ NFS4Inode::OpenAttr(OpenState* state, const char* name, int mode, reply.GetFH(&state->fInfo.fHandle); - if (result != B_OK) + if (result != B_OK) { + fFileSystem->OpenOwnerSequenceUnlock(sequence); return result; + } break; } while (true); @@ -643,9 +658,10 @@ NFS4Inode::OpenAttr(OpenState* state, const char* name, int mode, state->fOpened = true; if (confirm) - return ConfirmOpen(fInfo.fHandle, state); + result = ConfirmOpen(fInfo.fHandle, state, &sequence); - return B_OK; + fFileSystem->OpenOwnerSequenceUnlock(sequence); + return result; } @@ -1035,27 +1051,29 @@ NFS4Inode::AcquireLock(OpenFileCookie* cookie, LockInfo* lockInfo, bool wait) status_t result = request.Send(); if (result != B_OK) { - fFileSystem->OpenOwnerSequenceUnlock(false); + fFileSystem->OpenOwnerSequenceUnlock(sequence); return result; } ReplyInterpreter &reply = request.Reply(); + sequence += IncrementSequence(reply.NFS4Error()); + reply.PutFH(); result = reply.Lock(lockInfo); ownerLocker.Unlock(); if (wait && reply.NFS4Error() == NFS4ERR_DENIED) { - fFileSystem->OpenOwnerSequenceUnlock(); + fFileSystem->OpenOwnerSequenceUnlock(sequence); snooze_etc(sSecToBigTime(5), B_SYSTEM_TIMEBASE, B_RELATIVE_TIMEOUT); sequence = fFileSystem->OpenOwnerSequenceLock(); continue; } - if (HandleErrors(reply.NFS4Error(), serv, cookie)) + if (HandleErrors(reply.NFS4Error(), serv, cookie, NULL, &sequence)) continue; - fFileSystem->OpenOwnerSequenceUnlock(); + fFileSystem->OpenOwnerSequenceUnlock(sequence); if (result != B_OK) return result; diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp index fc5aecfb3e..67cdb4ea6b 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp @@ -30,37 +30,63 @@ NFS4Object::HandleErrors(uint32 nfs4Error, RPC::Server* serv, // server needs more time, we need to wait case NFS4ERR_LOCKED: case NFS4ERR_DELAY: + if (sequence != NULL) + fFileSystem->OpenOwnerSequenceUnlock(*sequence); + if (cookie == NULL) { snooze_etc(sSecToBigTime(5), B_SYSTEM_TIMEBASE, B_RELATIVE_TIMEOUT); + + if (sequence != NULL) + *sequence = fFileSystem->OpenOwnerSequenceLock(); + return true; } else if ((cookie->fMode & O_NONBLOCK) == 0) { status_t result = acquire_sem_etc(cookie->fSnoozeCancel, 1, B_RELATIVE_TIMEOUT, sSecToBigTime(5)); + + if (sequence != NULL) + *sequence = fFileSystem->OpenOwnerSequenceLock(); + if (result != B_TIMED_OUT) { release_sem(cookie->fSnoozeCancel); - return false; + return true; } - return true; + return false; } + + if (sequence != NULL) + *sequence = fFileSystem->OpenOwnerSequenceLock(); return false; // server is in grace period, we need to wait case NFS4ERR_GRACE: leaseTime = fFileSystem->NFSServer()->LeaseTime(); + if (sequence != NULL) + fFileSystem->OpenOwnerSequenceUnlock(*sequence); + if (cookie == NULL) { snooze_etc(sSecToBigTime(leaseTime) / 3, B_SYSTEM_TIMEBASE, B_RELATIVE_TIMEOUT); + if (sequence != NULL) + *sequence = fFileSystem->OpenOwnerSequenceLock(); 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 (sequence != NULL) + *sequence = fFileSystem->OpenOwnerSequenceLock(); + if (result != B_TIMED_OUT) { release_sem(cookie->fSnoozeCancel); - return false; + return true; } - return true; + return false; } + + if (sequence != NULL) + *sequence = fFileSystem->OpenOwnerSequenceLock(); return false; // server has rebooted, reclaim share and try again @@ -68,13 +94,12 @@ NFS4Object::HandleErrors(uint32 nfs4Error, RPC::Server* serv, case NFS4ERR_STALE_STATEID: if (state != NULL) { if (sequence != NULL) - fFileSystem->OpenOwnerSequenceUnlock(false); + fFileSystem->OpenOwnerSequenceUnlock(*sequence); fFileSystem->NFSServer()->ServerRebooted(state->fClientID); -dprintf("returned rebooted\n"); if (sequence != NULL) *sequence = fFileSystem->OpenOwnerSequenceLock(); -dprintf("locked again\n"); + return true; } return false; @@ -106,9 +131,9 @@ dprintf("locked again\n"); status_t -NFS4Object::ConfirmOpen(const FileHandle& fh, OpenState* state) +NFS4Object::ConfirmOpen(const FileHandle& fh, OpenState* state, + uint32* sequence) { - uint32 sequence = fFileSystem->OpenOwnerSequenceLock(); do { RPC::Server* serv = fFileSystem->Server(); Request request(serv); @@ -116,21 +141,19 @@ NFS4Object::ConfirmOpen(const FileHandle& fh, OpenState* state) RequestBuilder& req = request.Builder(); req.PutFH(fh); - req.OpenConfirm(sequence, state->fStateID, state->fStateSeq); + req.OpenConfirm(*sequence, state->fStateID, state->fStateSeq); status_t result = request.Send(); - if (result != B_OK) { - fFileSystem->OpenOwnerSequenceUnlock(false); + if (result != B_OK) return result; - } ReplyInterpreter& reply = request.Reply(); + *sequence += IncrementSequence(reply.NFS4Error()); + if (HandleErrors(reply.NFS4Error(), serv, NULL, state)) continue; - fFileSystem->OpenOwnerSequenceUnlock(); - reply.PutFH(); result = reply.OpenConfirm(&state->fStateSeq); if (result != B_OK) @@ -140,3 +163,16 @@ NFS4Object::ConfirmOpen(const FileHandle& fh, OpenState* state) } while (true); } + +uint32 +NFS4Object::IncrementSequence(uint32 error) +{ + if (error != NFS4ERR_STALE_CLIENTID && error != NFS4ERR_STALE_STATEID + && error != NFS4ERR_BAD_STATEID && error != NFS4ERR_BAD_SEQID + && error != NFS4ERR_BADXDR && error != NFS4ERR_RESOURCE + && error != NFS4ERR_NOFILEHANDLE) + return 1; + + return 0; +} + diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Object.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Object.h index 817b1c2c65..8cb927f118 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Object.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Object.h @@ -18,14 +18,17 @@ class OpenState; class NFS4Object { public: - bool HandleErrors(uint32 nfs4Error, RPC::Server* serv, - OpenStateCookie* cookie = NULL, OpenState* state = NULL, - uint32* sequence = NULL); + bool HandleErrors(uint32 nfs4Error, RPC::Server* serv, + OpenStateCookie* cookie = NULL, + OpenState* state = NULL, uint32* sequence = NULL); - status_t ConfirmOpen(const FileHandle& fileHandle, OpenState* state); + status_t ConfirmOpen(const FileHandle& fileHandle, + OpenState* state, uint32* sequence); - FileInfo fInfo; - FileSystem* fFileSystem; + static uint32 IncrementSequence(uint32 error); + + FileInfo fInfo; + FileSystem* fFileSystem; }; diff --git a/src/add-ons/kernel/file_systems/nfs4/OpenState.cpp b/src/add-ons/kernel/file_systems/nfs4/OpenState.cpp index 62c93bba02..b311cebcab 100644 --- a/src/add-ons/kernel/file_systems/nfs4/OpenState.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/OpenState.cpp @@ -143,10 +143,10 @@ OpenState::Reclaim(uint64 newClientID) if (fClientID == newClientID) return B_OK; fClientID = newClientID; -dprintf("reclaim start\n"); + _ReclaimOpen(newClientID); _ReclaimLocks(newClientID); -dprintf("reclaim end\n"); + return B_OK; } @@ -154,13 +154,12 @@ dprintf("reclaim end\n"); status_t OpenState::_ReclaimOpen(uint64 newClientID) { - dprintf("reclaim %s\n", fInfo.fName); - bool confirm; OpenDelegationData delegation; delegation.fType = OPEN_DELEGATE_NONE; delegation.fRecall = false; + status_t result; uint32 sequence = fFileSystem->OpenOwnerSequenceLock(); OpenDelegation delegType = fDelegation != NULL ? fDelegation->Type() : OPEN_DELEGATE_NONE; @@ -174,24 +173,26 @@ OpenState::_ReclaimOpen(uint64 newClientID) OPEN4_NOCREATE, fFileSystem->OpenOwner(), NULL, NULL, 0, false, delegType); - status_t result = request.Send(); + result = request.Send(); if (result != B_OK) { - fFileSystem->OpenOwnerSequenceUnlock(false); + fFileSystem->OpenOwnerSequenceUnlock(sequence); return result; } ReplyInterpreter& reply = request.Reply(); + sequence += IncrementSequence(reply.NFS4Error()); + if (HandleErrors(reply.NFS4Error(), server, NULL, NULL, &sequence)) continue; - fFileSystem->OpenOwnerSequenceUnlock(); - reply.PutFH(); result = reply.Open(fStateID, &fStateSeq, &confirm, &delegation); - if (result != B_OK) + if (result != B_OK) { + fFileSystem->OpenOwnerSequenceUnlock(sequence); return result; + } break; } while (true); @@ -207,17 +208,16 @@ OpenState::_ReclaimOpen(uint64 newClientID) } if (confirm) - return ConfirmOpen(fInfo.fHandle, this); + result = ConfirmOpen(fInfo.fHandle, this, &sequence); - return B_OK; + fFileSystem->OpenOwnerSequenceUnlock(sequence); + return result; } status_t OpenState::_ReclaimLocks(uint64 newClientID) { - dprintf("reclaim locks %s\n", fInfo.fName); - MutexLocker _(fLocksLock); LockInfo* linfo = fLocks; while (linfo != NULL) { @@ -279,15 +279,17 @@ OpenState::Close() status_t result = request.Send(); if (result != B_OK) { - fFileSystem->OpenOwnerSequenceUnlock(false); + fFileSystem->OpenOwnerSequenceUnlock(sequence); return result; } ReplyInterpreter& reply = request.Reply(); + sequence += IncrementSequence(reply.NFS4Error()); + if (HandleErrors(reply.NFS4Error(), serv, NULL, this, &sequence)) continue; - fFileSystem->OpenOwnerSequenceUnlock(); + fFileSystem->OpenOwnerSequenceUnlock(sequence); reply.PutFH(); From 6713e36b1d802e8775d9fb168a6fcb4e2f418d28 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Tue, 14 Aug 2012 04:26:28 +0200 Subject: [PATCH 189/252] nfs4: Setting owner and owner group at creation is not needed --- .../kernel/file_systems/nfs4/NFS4Inode.cpp | 43 +------------------ 1 file changed, 2 insertions(+), 41 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp index 79a79d8189..62a9acc1c5 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp @@ -403,7 +403,6 @@ NFS4Inode::CreateFile(const char* name, int mode, int perms, OpenState* state, bool confirm; status_t result; - bool badOwner = false; uint32 sequence = fFileSystem->OpenOwnerSequenceLock(); do { state->fClientID = fFileSystem->NFSServer()->ClientId(); @@ -414,7 +413,7 @@ NFS4Inode::CreateFile(const char* name, int mode, int perms, OpenState* state, req.PutFH(fInfo.fHandle); - AttrValue cattr[4]; + AttrValue cattr[2]; uint32 i = 0; if ((mode & O_TRUNC) == O_TRUNC) { cattr[i].fAttribute = FATTR4_SIZE; @@ -427,20 +426,6 @@ NFS4Inode::CreateFile(const char* name, int mode, int perms, OpenState* state, cattr[i].fData.fValue32 = perms; 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.Open(CLAIM_NULL, sequence, sModeToAccess(mode), state->fClientID, OPEN4_CREATE, fFileSystem->OpenOwner(), name, cattr, i, (mode & O_EXCL) == O_EXCL); @@ -462,10 +447,6 @@ NFS4Inode::CreateFile(const char* name, int mode, int perms, OpenState* state, sequence += IncrementSequence(reply.NFS4Error()); - if (reply.NFS4Error() == NFS4ERR_BADOWNER) { - badOwner = true; - continue; - } if (HandleErrors(reply.NFS4Error(), serv, NULL, state, &sequence)) continue; @@ -735,8 +716,6 @@ status_t NFS4Inode::CreateObject(const char* name, const char* path, int mode, FileType type, ChangeInfo* changeInfo, uint64* fileID, FileHandle* handle) { - bool badOwner = false; - do { RPC::Server* serv = fFileSystem->Server(); Request request(serv); @@ -745,26 +724,12 @@ NFS4Inode::CreateObject(const char* name, const char* path, int mode, req.PutFH(fInfo.fHandle); uint32 i = 0; - AttrValue cattr[3]; + AttrValue cattr[1]; 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++; - } - switch (type) { case NF4DIR: req.Create(NF4DIR, name, cattr, i); @@ -786,10 +751,6 @@ NFS4Inode::CreateObject(const char* name, const char* path, int mode, ReplyInterpreter& reply = request.Reply(); - if (reply.NFS4Error() == NFS4ERR_BADOWNER) { - badOwner = true; - continue; - } if (HandleErrors(reply.NFS4Error(), serv)) continue; From a5ae9b4752c300bcc39d9531581cbfae2525aec3 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Wed, 15 Aug 2012 00:09:41 +0200 Subject: [PATCH 190/252] nfs4: Do not repeat OPENATTR requests if not supported --- .../kernel/file_systems/nfs4/FileSystem.cpp | 1 + .../kernel/file_systems/nfs4/FileSystem.h | 18 ++++++++++++++++++ .../kernel/file_systems/nfs4/InodeDir.cpp | 6 ++++++ 3 files changed, 25 insertions(+) diff --git a/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp b/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp index d211299d9e..5c28b92d1c 100644 --- a/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp @@ -27,6 +27,7 @@ FileSystem::FileSystem() fPrev(NULL), fOpenCount(0), fOpenOwnerSequence(0), + fNamedAttrs(true), fPath(NULL), fRoot(NULL), fId(1) diff --git a/src/add-ons/kernel/file_systems/nfs4/FileSystem.h b/src/add-ons/kernel/file_systems/nfs4/FileSystem.h index 10850e96b2..3a2dfaceea 100644 --- a/src/add-ons/kernel/file_systems/nfs4/FileSystem.h +++ b/src/add-ons/kernel/file_systems/nfs4/FileSystem.h @@ -62,6 +62,9 @@ public: inline uint32 OpenOwnerSequenceLock(); inline void OpenOwnerSequenceUnlock(uint32 sequence); + inline bool NamedAttrs(); + inline void SetNamedAttrs(bool attrs); + FileSystem* fNext; FileSystem* fPrev; private: @@ -83,6 +86,7 @@ private: uint32 fExpireType; uint32 fSupAttrs[2]; + bool fNamedAttrs; FileSystemId fFsId; const char* fPath; @@ -205,5 +209,19 @@ FileSystem::OpenOwnerSequenceUnlock(uint32 sequence) } +inline bool +FileSystem::NamedAttrs() +{ + return fNamedAttrs; +} + + +inline void +FileSystem::SetNamedAttrs(bool attrs) +{ + fNamedAttrs = attrs; +} + + #endif // FILESYSTEM_H diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp b/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp index f2c83fe6ab..d78d28fd55 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp @@ -62,10 +62,16 @@ Inode::OpenAttrDir(OpenDirCookie* cookie) status_t Inode::LoadAttrDirHandle() { + if (!fFileSystem->NamedAttrs()) + return B_UNSUPPORTED; + if (fInfo.fAttrDir.fSize == 0) { FileHandle handle; status_t result = NFS4Inode::OpenAttrDir(&handle); + if (result == B_UNSUPPORTED) + fFileSystem->SetNamedAttrs(false); + if (result != B_OK) return result; From ff4d16ded4782a2967ffa2413761c078516b2ae6 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Wed, 15 Aug 2012 01:22:35 +0200 Subject: [PATCH 191/252] nfs4: Use reserved port if possible --- .../kernel/file_systems/nfs4/Connection.cpp | 48 ++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Connection.cpp b/src/add-ons/kernel/file_systems/nfs4/Connection.cpp index 6b38b04dab..9e9a78a63a 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Connection.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Connection.cpp @@ -24,6 +24,8 @@ #define LAST_FRAGMENT 0x80000000 #define MAX_PACKET_SIZE 65535 +#define NFS_MIN_PORT 665 + bool ServerAddress::operator==(const ServerAddress& address) @@ -507,6 +509,50 @@ Connection::Connect() if (fSocket < 0) return errno; + status_t result; + uint16 port, attempt = 0; + + sockaddr_in addr; + sockaddr_in6 addr6; + switch (address.sa_family) { + case AF_INET: + memset(&addr, 0, sizeof(addr)); + addr.sin_len = sizeof(addr); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = INADDR_ANY; + break; + case AF_INET6: + memset(&addr6, 0, sizeof(addr6)); + addr6.sin6_len = sizeof(addr6); + addr6.sin6_family = AF_INET6; + break; + } + + do { + port = rand() % (IPPORT_RESERVED - NFS_MIN_PORT); + port += NFS_MIN_PORT; + + if (attempt == 9) + port = 0; + attempt++; + + switch (address.sa_family) { + case AF_INET: + addr.sin_port = htons(port); + result = bind(fSocket, (struct sockaddr*)&addr, sizeof(addr)); + break; + case AF_INET6: + addr6.sin6_port = htons(port); + result = bind(fSocket, (struct sockaddr*)&addr6, sizeof(addr6)); + break; + } + } while (attempt <= 10 && result != B_OK); + + if (attempt > 10) { + close(fSocket); + return result; + } + socklen_t addressSize; switch (address.sa_family) { case AF_INET: @@ -519,7 +565,7 @@ Connection::Connect() return B_BAD_VALUE; } - status_t result = connect(fSocket, &address, addressSize); + result = connect(fSocket, &address, addressSize); if (result != 0) { result = errno; close(fSocket); From 70472e11d37500a8cb434906f20254046bef0f5e Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Wed, 15 Aug 2012 04:11:25 +0200 Subject: [PATCH 192/252] nfs4: Add basic emulation of named attributes --- .../kernel/file_systems/nfs4/InodeDir.cpp | 81 +++++++++++++++--- .../kernel/file_systems/nfs4/InodeRegular.cpp | 49 +++++++++-- .../kernel/file_systems/nfs4/NFS4Inode.cpp | 85 ++++++++++++------- .../kernel/file_systems/nfs4/NFS4Inode.h | 5 +- .../kernel/file_systems/nfs4/OpenState.cpp | 3 +- .../file_systems/nfs4/ReplyInterpreter.cpp | 1 + 6 files changed, 169 insertions(+), 55 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp b/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp index d78d28fd55..33e782251c 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp @@ -62,22 +62,41 @@ Inode::OpenAttrDir(OpenDirCookie* cookie) status_t Inode::LoadAttrDirHandle() { - if (!fFileSystem->NamedAttrs()) - return B_UNSUPPORTED; + if (fInfo.fAttrDir.fSize != 0) + return B_OK; - if (fInfo.fAttrDir.fSize == 0) { - FileHandle handle; + FileHandle handle; + status_t result; + if (!fFileSystem->NamedAttrs()) { + char* attrDir + = reinterpret_cast(malloc(strlen(fInfo.fName) + 32)); + if (attrDir == NULL) + return B_NO_MEMORY; + strcpy(attrDir, "."); + strcat(attrDir, fInfo.fName); + strcat(attrDir, "-haiku-attrs"); - status_t result = NFS4Inode::OpenAttrDir(&handle); + result = NFS4Inode::LookUp(attrDir, NULL, NULL, &handle, true); + if (result == B_ENTRY_NOT_FOUND) { + ChangeInfo change; + struct stat st; + Stat(&st); + st.st_mode |= S_IXUSR | S_IXGRP | S_IXOTH; + result = NFS4Inode::CreateObject(attrDir, NULL, st.st_mode, NF4DIR, + &change, NULL, &handle, true); + } + + free(attrDir); + } else { + result = NFS4Inode::OpenAttrDir(&handle); if (result == B_UNSUPPORTED) fFileSystem->SetNamedAttrs(false); - - if (result != B_OK) - return result; - - fInfo.fAttrDir = handle; } + if (result != B_OK) + return result; + + fInfo.fAttrDir = handle; return B_OK; } @@ -156,6 +175,31 @@ Inode::ReadDirUp(struct dirent* de, uint32 pos, uint32 size) } +static char* +FileToAttrName(const char* path) +{ + char* name = strdup(path); + if (name == NULL) + return NULL; + + char* current = strpbrk(name, "#$"); + while (current != NULL) { + switch (*current) { + case '#': + *current = '/'; + break; + case '$': + *current = ':'; + break; + } + current = strpbrk(name, "#$"); + } + + return name; +} + + + status_t Inode::GetDirSnapshot(DirectoryCacheSnapshot** _snapshot, OpenDirCookie* cookie, uint64* _change, bool attribute) @@ -189,6 +233,9 @@ Inode::GetDirSnapshot(DirectoryCacheSnapshot** _snapshot, if (*fsid != fFileSystem->FsId()) continue; + if (strstr(dirents[i].fName, "-haiku-attrs") != NULL) + continue; + ino_t id; if (!attribute) { if (dirents[i].fAttrCount == 2) @@ -198,7 +245,19 @@ Inode::GetDirSnapshot(DirectoryCacheSnapshot** _snapshot, } else id = 0; - NameCacheEntry* entry = new NameCacheEntry(dirents[i].fName, id); + const char* name = dirents[i].fName; + if (attribute) + name = FileToAttrName(name); + if (name == NULL) { + delete snapshot; + delete[] dirents; + return B_NO_MEMORY; + } + + NameCacheEntry* entry = new NameCacheEntry(name, id); + if (attribute) + free(const_cast(name)); + if (entry == NULL || entry->fName == NULL) { if (entry->fName == NULL) delete entry; diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp index 5490ee0582..921d52a4e6 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp @@ -11,6 +11,7 @@ #include +#include #include #include @@ -192,9 +193,33 @@ Inode::Close(OpenFileCookie* cookie) } +static char* +AttrToFileName(const char* path) +{ + char* name = strdup(path); + if (name == NULL) + return NULL; + + char* current = strpbrk(name, "/:"); + while (current != NULL) { + switch (*current) { + case '/': + *current = '#'; + break; + case ':': + *current = '$'; + break; + } + current = strpbrk(name, "/:"); + } + + return name; +} + + status_t -Inode::OpenAttr(const char* name, int mode, OpenAttrCookie* cookie, bool create, - int32 type) +Inode::OpenAttr(const char* _name, int mode, OpenAttrCookie* cookie, + bool create, int32 type) { (void)type; @@ -202,6 +227,11 @@ Inode::OpenAttr(const char* name, int mode, OpenAttrCookie* cookie, bool create, if (result != B_OK) return result; + char* name = AttrToFileName(_name); + if (name == NULL) + return B_NO_MEMORY; + MemoryDeleter nameDeleter(name); + OpenDelegationData data; data.fType = OPEN_DELEGATE_NONE; @@ -209,8 +239,9 @@ Inode::OpenAttr(const char* name, int mode, OpenAttrCookie* cookie, bool create, if (state == NULL) return B_NO_MEMORY; - state->fInfo.fName = name; + state->fInfo.fName = strdup(name); state->fInfo.fParent = fInfo.fAttrDir; + state->fFileSystem = fFileSystem; result = NFS4Inode::OpenAttr(state, name, mode, &data, create); if (result != B_OK) { delete state; @@ -225,8 +256,7 @@ Inode::OpenAttr(const char* name, int mode, OpenAttrCookie* cookie, bool create, if (data.fType != OPEN_DELEGATE_NONE) { Delegation* delegation - = new(std::nothrow) Delegation(data, this, fOpenState->fClientID, - true); + = new(std::nothrow) Delegation(data, this, state->fClientID, true); if (delegation != NULL) { delegation->fInfo = state->fInfo; delegation->fFileSystem = fFileSystem; @@ -235,7 +265,7 @@ Inode::OpenAttr(const char* name, int mode, OpenAttrCookie* cookie, bool create, } } - if ((mode & O_TRUNC) == O_TRUNC) { + if (create || (mode & O_TRUNC) == O_TRUNC) { struct stat st; st.st_size = 0; WriteStat(&st, B_STAT_SIZE, cookie); @@ -248,8 +278,11 @@ Inode::OpenAttr(const char* name, int mode, OpenAttrCookie* cookie, bool create, status_t Inode::CloseAttr(OpenAttrCookie* cookie) { - cookie->fOpenState->fDelegation->GiveUp(); - fFileSystem->RemoveDelegation(cookie->fOpenState->fDelegation); + if (cookie->fOpenState->fDelegation != NULL) { + cookie->fOpenState->fDelegation->GiveUp(); + fFileSystem->RemoveDelegation(cookie->fOpenState->fDelegation); + } + delete cookie->fOpenState->fDelegation; delete cookie->fOpenState; return B_OK; diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp index 62a9acc1c5..6f66c32d2e 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp @@ -107,17 +107,22 @@ NFS4Inode::Access(uint32* allowed) status_t NFS4Inode::LookUp(const char* name, uint64* change, uint64* fileID, - FileHandle* handle) + FileHandle* handle, bool parent) { do { RPC::Server* serv = fFileSystem->Server(); Request request(serv); RequestBuilder& req = request.Builder(); - req.PutFH(fInfo.fHandle); + if (parent) + req.PutFH(fInfo.fParent); + else + req.PutFH(fInfo.fHandle); - Attribute dirAttr[] = { FATTR4_CHANGE }; - req.GetAttr(dirAttr, sizeof(dirAttr) / sizeof(Attribute)); + if (change != NULL) { + Attribute dirAttr[] = { FATTR4_CHANGE }; + req.GetAttr(dirAttr, sizeof(dirAttr) / sizeof(Attribute)); + } if (!strcmp(name, "..")) req.LookUpUp(); @@ -142,12 +147,14 @@ NFS4Inode::LookUp(const char* name, uint64* change, uint64* fileID, AttrValue* values; uint32 count; - result = reply.GetAttr(&values, &count); - if (result != B_OK) - return result; + if (change != NULL) { + result = reply.GetAttr(&values, &count); + if (result != B_OK) + return result; - *change = values[0].fData.fValue64; - delete[] values; + *change = values[0].fData.fValue64; + delete[] values; + } if (!strcmp(name, "..")) result = reply.LookUpUp(); @@ -170,10 +177,13 @@ NFS4Inode::LookUp(const char* name, uint64* change, uint64* fileID, return B_ENTRY_NOT_FOUND; } - if (count < 2 || values[1].fAttribute != FATTR4_FILEID) - *fileID = fFileSystem->AllocFileId(); - else - *fileID = values[1].fData.fValue64; + if (fileID != NULL) { + if (count < 2 || values[1].fAttribute != FATTR4_FILEID) + *fileID = fFileSystem->AllocFileId(); + else + *fileID = values[1].fData.fValue64; + } + delete[] values; return B_OK; @@ -536,11 +546,11 @@ NFS4Inode::OpenFile(OpenState* state, int mode, OpenDelegationData* delegation) ReplyInterpreter& reply = request.Reply(); + sequence += IncrementSequence(reply.NFS4Error()); + if (HandleErrors(reply.NFS4Error(), serv, NULL, state, &sequence)) continue; - sequence += IncrementSequence(reply.NFS4Error()); - // Verify if the file we want to open is the file this Inode // represents. if (fFileSystem->IsAttrSupported(FATTR4_FILEID) || @@ -617,11 +627,11 @@ NFS4Inode::OpenAttr(OpenState* state, const char* name, int mode, ReplyInterpreter& reply = request.Reply(); - if (HandleErrors(reply.NFS4Error(), serv, NULL, state)) - continue; - sequence += IncrementSequence(reply.NFS4Error()); + if (HandleErrors(reply.NFS4Error(), serv, NULL, state, &sequence)) + continue; + reply.PutFH(); result = reply.Open(state->fStateID, &state->fStateSeq, &confirm, delegation); @@ -639,7 +649,7 @@ NFS4Inode::OpenAttr(OpenState* state, const char* name, int mode, state->fOpened = true; if (confirm) - result = ConfirmOpen(fInfo.fHandle, state, &sequence); + result = ConfirmOpen(state->fInfo.fHandle, state, &sequence); fFileSystem->OpenOwnerSequenceUnlock(sequence); return result; @@ -714,14 +724,18 @@ NFS4Inode::WriteFile(OpenStateCookie* cookie, OpenState* state, uint64 position, status_t NFS4Inode::CreateObject(const char* name, const char* path, int mode, - FileType type, ChangeInfo* changeInfo, uint64* fileID, FileHandle* handle) + FileType type, ChangeInfo* changeInfo, uint64* fileID, FileHandle* handle, + bool parent) { do { RPC::Server* serv = fFileSystem->Server(); Request request(serv); RequestBuilder& req = request.Builder(); - req.PutFH(fInfo.fHandle); + if (parent) + req.PutFH(fInfo.fParent); + else + req.PutFH(fInfo.fHandle); uint32 i = 0; AttrValue cattr[1]; @@ -742,8 +756,11 @@ NFS4Inode::CreateObject(const char* name, const char* path, int mode, } req.GetFH(); - Attribute attr[] = { FATTR4_FILEID }; - req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); + + if (fileID != NULL) { + Attribute attr[] = { FATTR4_FILEID }; + req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); + } status_t result = request.Send(); if (result != B_OK) @@ -764,18 +781,20 @@ NFS4Inode::CreateObject(const char* name, const char* path, int mode, if (result != B_OK) return result; - AttrValue* values; - uint32 count; - result = reply.GetAttr(&values, &count); - if (result != B_OK) - return result; + if (fileID != NULL) { + AttrValue* values; + uint32 count; + result = reply.GetAttr(&values, &count); + if (result != B_OK) + return result; - if (count == 0) - *fileID = fFileSystem->AllocFileId(); - else - *fileID = values[0].fData.fValue64; + if (count == 0) + *fileID = fFileSystem->AllocFileId(); + else + *fileID = values[0].fData.fValue64; - delete[] values; + delete[] values; + } return B_OK; } while (true); diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h index 110cce7ffe..fcb109052f 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h @@ -31,7 +31,7 @@ protected: status_t CommitWrites(); status_t LookUp(const char* name, uint64* change, uint64* fileID, - FileHandle* handle); + FileHandle* handle, bool parent = false); status_t Link(Inode* dir, const char* name, ChangeInfo* changeInfo); @@ -65,7 +65,8 @@ protected: status_t CreateObject(const char* name, const char* path, int mode, FileType type, ChangeInfo* changeInfo, - uint64* fileID, FileHandle* handle); + uint64* fileID, FileHandle* handle, + bool parent = false); status_t RemoveObject(const char* name, FileType type, ChangeInfo* changeInfo, uint64* fileID); diff --git a/src/add-ons/kernel/file_systems/nfs4/OpenState.cpp b/src/add-ons/kernel/file_systems/nfs4/OpenState.cpp index b311cebcab..7de9b42d04 100644 --- a/src/add-ons/kernel/file_systems/nfs4/OpenState.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/OpenState.cpp @@ -32,7 +32,8 @@ OpenState::OpenState() OpenState::~OpenState() { - fFileSystem->RemoveOpenFile(this); + if (fOpened) + fFileSystem->RemoveOpenFile(this); Close(); mutex_destroy(&fLock); diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp index 581282753c..6f04552ab0 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp @@ -34,6 +34,7 @@ FSLocations::~FSLocations() AttrValue::AttrValue() : + fAttribute(0), fFreePointer(false) { } From c0344ea198e280a3e8f23191262e2d7fffe9ff0c Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Wed, 15 Aug 2012 04:22:18 +0200 Subject: [PATCH 193/252] nfs4: Get correct change value for attribute directories --- src/add-ons/kernel/file_systems/nfs4/DirectoryCache.cpp | 2 +- src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp | 7 +++++-- src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.cpp b/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.cpp index e7062c0567..325a7646a3 100644 --- a/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.cpp @@ -179,7 +179,7 @@ status_t DirectoryCache::Revalidate() { uint64 change; - if (fInode->GetChangeInfo(&change) == B_OK && change == fChange) { + if (fInode->GetChangeInfo(&change, true) == B_OK && change == fChange) { fExpireTime = system_time() + kExpirationTime; return B_OK; } diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp index 6f66c32d2e..145c50f842 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp @@ -14,14 +14,17 @@ status_t -NFS4Inode::GetChangeInfo(uint64* change) +NFS4Inode::GetChangeInfo(uint64* change, bool attrDir) { do { RPC::Server* serv = fFileSystem->Server(); Request request(serv); RequestBuilder& req = request.Builder(); - req.PutFH(fInfo.fHandle); + if (attrDir) + req.PutFH(fInfo.fAttrDir); + else + req.PutFH(fInfo.fHandle); Attribute attr[] = { FATTR4_CHANGE }; req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h index fcb109052f..62db373c8a 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h @@ -22,7 +22,7 @@ class NFS4Inode : protected NFS4Object { public: - status_t GetChangeInfo(uint64* change); + status_t GetChangeInfo(uint64* change, bool attrDir = false); status_t ReadLink(void* buffer, size_t* length); protected: From 45cd64efd9124013b28ce9c232f4d9c42df6cd56 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Thu, 16 Aug 2012 01:30:24 +0200 Subject: [PATCH 194/252] nfs4: Fix amount of data written when using AIO --- src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp | 4 ++-- src/add-ons/kernel/file_systems/nfs4/WorkQueue.cpp | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp index 921d52a4e6..4d1b943e4e 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp @@ -353,8 +353,8 @@ Inode::WriteDirect(OpenStateCookie* cookie, off_t pos, const void* _buffer, while (size < *_length) { uint32 len = *_length - size; - status_t result = WriteFile(cookie, state, pos + size, - &len, buffer + size, attribute); + status_t result = WriteFile(cookie, state, pos + size, &len, + buffer + size, attribute); if (result != B_OK) { if (size == 0) return result; diff --git a/src/add-ons/kernel/file_systems/nfs4/WorkQueue.cpp b/src/add-ons/kernel/file_systems/nfs4/WorkQueue.cpp index 9d387248cf..c576b96896 100644 --- a/src/add-ons/kernel/file_systems/nfs4/WorkQueue.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/WorkQueue.cpp @@ -153,8 +153,10 @@ WorkQueue::JobIO(IORequestArgs* args) uint64 size = 0; status_t result; if (io_request_is_write(args->fRequest)) { - result = read_from_io_request(args->fRequest, buffer, length); + if (offset + length > args->fInode->MaxFileSize()) + length = args->fInode->MaxFileSize() - offset; + result = read_from_io_request(args->fRequest, buffer, length); do { size_t bytesWritten = length - size; result = args->fInode->WriteDirect(NULL, offset + size, From cd2c1203d3725b5a4fc7e31b03a8021f635f0642 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Thu, 16 Aug 2012 02:01:34 +0200 Subject: [PATCH 195/252] dns_resolver: Fix addrinfo entries relocation --- .../kernel/network/dns_resolver/kernel_add_on/dns_resolver.cpp | 2 +- src/add-ons/kernel/network/dns_resolver/server/main.cpp | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/add-ons/kernel/network/dns_resolver/kernel_add_on/dns_resolver.cpp b/src/add-ons/kernel/network/dns_resolver/kernel_add_on/dns_resolver.cpp index eb58f5a143..6c1e0c9872 100644 --- a/src/add-ons/kernel/network/dns_resolver/kernel_add_on/dns_resolver.cpp +++ b/src/add-ons/kernel/network/dns_resolver/kernel_add_on/dns_resolver.cpp @@ -94,7 +94,7 @@ dns_resolver_uninit() static void -RelocateEntries(struct addrinfo *addr) +RelocateEntries(struct addrinfo* addr) { char* generalOffset = reinterpret_cast(addr); diff --git a/src/add-ons/kernel/network/dns_resolver/server/main.cpp b/src/add-ons/kernel/network/dns_resolver/server/main.cpp index 0c816ca391..8082488f5a 100644 --- a/src/add-ons/kernel/network/dns_resolver/server/main.cpp +++ b/src/add-ons/kernel/network/dns_resolver/server/main.cpp @@ -94,7 +94,8 @@ GetAddrInfo(const char* buffer) } addrinfo* next = current->ai_next; - current->ai_next = reinterpret_cast(addrPos) + 1; + if (next != NULL) + current->ai_next = reinterpret_cast(addrPos) + 1; memcpy(reply + addrPos, current, sizeof(addrinfo)); addrPos += sizeof(addrinfo); From 376eef4a9b32abb57a38238a7e9eed5268f3079a Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Thu, 16 Aug 2012 02:24:53 +0200 Subject: [PATCH 196/252] nfs4: Add node to inode to file handle map before notifying --- .../file_systems/nfs4/DirectoryCache.cpp | 19 +++++++++++++++++++ src/add-ons/kernel/file_systems/nfs4/Inode.h | 3 +-- .../kernel/file_systems/nfs4/NFS4Inode.h | 2 +- .../kernel/file_systems/nfs4/NFS4Object.cpp | 11 ++++++----- 4 files changed, 27 insertions(+), 8 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.cpp b/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.cpp index 325a7646a3..b9483a0c07 100644 --- a/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.cpp @@ -252,6 +252,25 @@ DirectoryCache::NotifyChanges(DirectoryCacheSnapshot* oldSnapshot, } else { notify_entry_created(fInode->GetFileSystem()->DevId(), fInode->ID(), newCurrent->fName, newCurrent->fNode); + + FileInfo fi; + fi.fFileId = newCurrent->fNode; + fi.fParent = fInode->fInfo.fHandle; + fi.fName = strdup(newCurrent->fName); + if (fi.fName != NULL) { + size_t pathLength = strlen(newCurrent->fName) + 2 + + strlen(fInode->fInfo.fPath); + char* path = reinterpret_cast(malloc(pathLength)); + if (path != NULL) { + strcpy(path, fInode->fInfo.fPath); + strcat(path, "/"); + strcat(path, newCurrent->fName); + fi.fPath = path; + + fInode->GetFileSystem()->InoIdMap()->AddEntry(fi, + Inode::FileIdToInoT(newCurrent->fNode)); + } + } } } else oldSnapshot->fEntries.Remove(prev, oldCurrent); diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h b/src/add-ons/kernel/file_systems/nfs4/Inode.h index ab8feecec4..d4d16acdae 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -109,6 +109,7 @@ public: status_t LoadAttrDirHandle(); + static inline ino_t FileIdToInoT(uint64 fileid); protected: Inode(); @@ -133,8 +134,6 @@ protected: static inline status_t CheckLockType(short ltype, uint32 mode); - static inline ino_t FileIdToInoT(uint64 fileid); - private: uint32 fType; diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h index 62db373c8a..cd3c461c77 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h @@ -20,7 +20,7 @@ #include "ReplyInterpreter.h" -class NFS4Inode : protected NFS4Object { +class NFS4Inode : public NFS4Object { public: status_t GetChangeInfo(uint64* change, bool attrDir = false); status_t ReadLink(void* buffer, size_t* length); diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp index 67cdb4ea6b..e29379d825 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp @@ -50,9 +50,9 @@ NFS4Object::HandleErrors(uint32 nfs4Error, RPC::Server* serv, if (result != B_TIMED_OUT) { release_sem(cookie->fSnoozeCancel); - return true; + return false; } - return false; + return true; } if (sequence != NULL) @@ -80,9 +80,9 @@ NFS4Object::HandleErrors(uint32 nfs4Error, RPC::Server* serv, if (result != B_TIMED_OUT) { release_sem(cookie->fSnoozeCancel); - return true; + return false; } - return false; + return true; } if (sequence != NULL) @@ -104,7 +104,8 @@ NFS4Object::HandleErrors(uint32 nfs4Error, RPC::Server* serv, } return false; - // FileHandle has expired + // FileHandle has expired or is invalid + case NFS4ERR_BADHANDLE: case NFS4ERR_FHEXPIRED: if (fInfo.UpdateFileHandles(fFileSystem) == B_OK) return true; From a37a22884cd3f5b3442b1d88e6a0789f838de224 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Thu, 16 Aug 2012 02:52:15 +0200 Subject: [PATCH 197/252] nfs4: Let GenerateClientID take advantage of PeerAddress methods --- .../kernel/file_systems/nfs4/Connection.cpp | 67 +++++++++++-------- .../kernel/file_systems/nfs4/Connection.h | 33 ++++----- .../kernel/file_systems/nfs4/FileSystem.cpp | 4 +- .../file_systems/nfs4/RPCCallbackServer.h | 6 +- .../kernel/file_systems/nfs4/RPCServer.cpp | 6 +- .../kernel/file_systems/nfs4/RPCServer.h | 20 +++--- .../file_systems/nfs4/RequestBuilder.cpp | 47 +++---------- .../file_systems/nfs4/kernel_interface.cpp | 6 +- 8 files changed, 86 insertions(+), 103 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Connection.cpp b/src/add-ons/kernel/file_systems/nfs4/Connection.cpp index 9e9a78a63a..34d370d94e 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Connection.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Connection.cpp @@ -28,22 +28,22 @@ bool -ServerAddress::operator==(const ServerAddress& address) +PeerAddress::operator==(const PeerAddress& address) { return memcmp(&fAddress, &address.fAddress, sizeof(fAddress)) == 0 && fProtocol == address.fProtocol; } bool -ServerAddress::operator<(const ServerAddress& address) +PeerAddress::operator<(const PeerAddress& address) { int compare = memcmp(&fAddress, &address.fAddress, sizeof(fAddress)); return compare < 0 || (compare == 0 && fProtocol < address.fProtocol); } -ServerAddress& -ServerAddress::operator=(const ServerAddress& address) +PeerAddress& +PeerAddress::operator=(const PeerAddress& address) { fAddress = address.fAddress; fProtocol = address.fProtocol; @@ -51,7 +51,7 @@ ServerAddress::operator=(const ServerAddress& address) } -ServerAddress::ServerAddress() +PeerAddress::PeerAddress() : fProtocol(0) { @@ -60,7 +60,7 @@ ServerAddress::ServerAddress() const char* -ServerAddress::ProtocolString() const +PeerAddress::ProtocolString() const { static const char* tcpName = "tcp"; static const char* udpName = "udp"; @@ -78,7 +78,7 @@ ServerAddress::ProtocolString() const char* -ServerAddress::UniversalAddress() const +PeerAddress::UniversalAddress() const { const sockaddr* address = reinterpret_cast(&fAddress); @@ -98,7 +98,7 @@ ServerAddress::UniversalAddress() const socklen_t -ServerAddress::AddressSize() const +PeerAddress::AddressSize() const { switch (reinterpret_cast(&fAddress)->sa_family) { case AF_INET: @@ -112,7 +112,7 @@ ServerAddress::AddressSize() const uint16 -ServerAddress::Port() const +PeerAddress::Port() const { uint16 port; @@ -132,7 +132,7 @@ ServerAddress::Port() const void -ServerAddress::SetPort(uint16 port) +PeerAddress::SetPort(uint16 port) { port = htons(port); @@ -148,7 +148,7 @@ ServerAddress::SetPort(uint16 port) const void* -ServerAddress::InAddr() const +PeerAddress::InAddr() const { switch (reinterpret_cast(&fAddress)->sa_family) { case AF_INET: @@ -161,9 +161,22 @@ ServerAddress::InAddr() const } +size_t +PeerAddress::InAddrSize() const +{ + switch (reinterpret_cast(&fAddress)->sa_family) { + case AF_INET: + return sizeof(in_addr); + case AF_INET6: + return sizeof(in6_addr); + default: + return 0; + } +} + status_t -ServerAddress::ResolveName(const char* name, ServerAddress* address) +PeerAddress::ResolveName(const char* name, PeerAddress* address) { address->fProtocol = IPPROTO_TCP; @@ -210,39 +223,39 @@ ServerAddress::ResolveName(const char* name, ServerAddress* address) } -Connection::Connection(const ServerAddress& address) +Connection::Connection(const PeerAddress& address) : ConnectionBase(address) { } -ConnectionListener::ConnectionListener(const ServerAddress& address) +ConnectionListener::ConnectionListener(const PeerAddress& address) : ConnectionBase(address) { } -ConnectionBase::ConnectionBase(const ServerAddress& address) +ConnectionBase::ConnectionBase(const PeerAddress& address) : fWaitCancel(create_sem(0, NULL)), fSocket(-1), - fServerAddress(address) + fPeerAddress(address) { mutex_init(&fSocketLock, NULL); } -ConnectionStream::ConnectionStream(const ServerAddress& address) +ConnectionStream::ConnectionStream(const PeerAddress& address) : Connection(address) { } -ConnectionPacket::ConnectionPacket(const ServerAddress& address) +ConnectionPacket::ConnectionPacket(const PeerAddress& address) : Connection(address) { @@ -259,9 +272,9 @@ ConnectionBase::~ConnectionBase() status_t -ConnectionBase::GetLocalAddress(ServerAddress* address) +ConnectionBase::GetLocalAddress(PeerAddress* address) { - address->fProtocol = fServerAddress.fProtocol; + address->fProtocol = fPeerAddress.fProtocol; socklen_t addressSize = sizeof(address->fAddress); return getsockname(fSocket, (struct sockaddr*)&address->fAddress, @@ -443,7 +456,7 @@ ConnectionPacket::Receive(void** _buffer, uint32* _size) Connection* -Connection::CreateObject(const ServerAddress& address) +Connection::CreateObject(const PeerAddress& address) { switch (address.fProtocol) { case IPPROTO_TCP: @@ -457,7 +470,7 @@ Connection::CreateObject(const ServerAddress& address) status_t -Connection::Connect(Connection **_connection, const ServerAddress& address) +Connection::Connect(Connection **_connection, const PeerAddress& address) { Connection* conn = CreateObject(address); if (conn == NULL) @@ -477,7 +490,7 @@ Connection::Connect(Connection **_connection, const ServerAddress& address) status_t Connection::SetTo(Connection **_connection, int socket, - const ServerAddress& address) + const PeerAddress& address) { Connection* conn = CreateObject(address); if (conn == NULL) @@ -494,9 +507,9 @@ status_t Connection::Connect() { const sockaddr& address = - *reinterpret_cast(&fServerAddress); + *reinterpret_cast(&fPeerAddress); - switch (fServerAddress.fProtocol) { + switch (fPeerAddress.fProtocol) { case IPPROTO_TCP: fSocket = socket(address.sa_family, SOCK_STREAM, IPPROTO_TCP); break; @@ -619,7 +632,7 @@ ConnectionListener::Listen(ConnectionListener** listener, uint16 port) return errno; } - ServerAddress address; + PeerAddress address; address.fProtocol = IPPROTO_TCP; memset(&address.fAddress, 0, sizeof(address.fAddress)); @@ -663,7 +676,7 @@ ConnectionListener::AcceptConnection(Connection** connection) if (sock < 0) return errno; - ServerAddress address; + PeerAddress address; address.fProtocol = IPPROTO_TCP; address.fAddress = addr; diff --git a/src/add-ons/kernel/file_systems/nfs4/Connection.h b/src/add-ons/kernel/file_systems/nfs4/Connection.h index 7b21564ad6..b10cc9c2d7 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Connection.h +++ b/src/add-ons/kernel/file_systems/nfs4/Connection.h @@ -15,16 +15,16 @@ #include -struct ServerAddress { +struct PeerAddress { sockaddr_storage fAddress; int fProtocol; - bool operator==(const ServerAddress& address); - bool operator<(const ServerAddress& address); + bool operator==(const PeerAddress& address); + bool operator<(const PeerAddress& address); - ServerAddress& operator=(const ServerAddress& address); + PeerAddress& operator=(const PeerAddress& address); - ServerAddress(); + PeerAddress(); const char* ProtocolString() const; char* UniversalAddress() const; @@ -35,17 +35,18 @@ struct ServerAddress { uint16 Port() const; const void* InAddr() const; + size_t InAddrSize() const; static status_t ResolveName(const char* name, - ServerAddress* address); + PeerAddress* address); }; class ConnectionBase { public: - ConnectionBase(const ServerAddress& address); + ConnectionBase(const PeerAddress& address); virtual ~ConnectionBase(); - status_t GetLocalAddress(ServerAddress* address); + status_t GetLocalAddress(PeerAddress* address); void Disconnect(); @@ -54,15 +55,15 @@ protected: int fSocket; mutex fSocketLock; - const ServerAddress fServerAddress; + const PeerAddress fPeerAddress; }; class Connection : public ConnectionBase { public: static status_t Connect(Connection **connection, - const ServerAddress& address); + const PeerAddress& address); static status_t SetTo(Connection **connection, int socket, - const ServerAddress& address); + const PeerAddress& address); virtual status_t Send(const void* buffer, uint32 size) = 0; virtual status_t Receive(void** buffer, uint32* size) = 0; @@ -70,16 +71,16 @@ public: status_t Reconnect(); protected: - static Connection* CreateObject(const ServerAddress& address); + static Connection* CreateObject(const PeerAddress& address); - Connection(const ServerAddress& address); + Connection(const PeerAddress& address); status_t Connect(); }; class ConnectionStream : public Connection { public: - ConnectionStream(const ServerAddress& address); + ConnectionStream(const PeerAddress& address); virtual status_t Send(const void* buffer, uint32 size); virtual status_t Receive(void** buffer, uint32* size); @@ -87,7 +88,7 @@ public: class ConnectionPacket : public Connection { public: - ConnectionPacket(const ServerAddress& address); + ConnectionPacket(const PeerAddress& address); virtual status_t Send(const void* buffer, uint32 size); virtual status_t Receive(void** buffer, uint32* size); @@ -100,7 +101,7 @@ public: status_t AcceptConnection(Connection** connection); protected: - ConnectionListener(const ServerAddress& address); + ConnectionListener(const PeerAddress& address); }; #endif // CONNECTION_H diff --git a/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp b/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp index 5c28b92d1c..2adf0b7f4d 100644 --- a/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp @@ -224,10 +224,10 @@ FileSystem::Migrate(const RPC::Server* serv) reinterpret_cast(values[0].fData.fLocations); RPC::Server* server = fServer; - ServerAddress addr = fServer->ID(); + PeerAddress addr = fServer->ID(); for (uint32 i = 0; i < locs->fCount; i++) { for (uint32 j = 0; j < locs->fLocations[i].fCount; j++) { - if (ServerAddress::ResolveName(locs->fLocations[i].fLocations[j], + if (PeerAddress::ResolveName(locs->fLocations[i].fLocations[j], &addr) != B_OK) continue; diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCCallbackServer.h b/src/add-ons/kernel/file_systems/nfs4/RPCCallbackServer.h index d114c652de..8a5f67b816 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RPCCallbackServer.h +++ b/src/add-ons/kernel/file_systems/nfs4/RPCCallbackServer.h @@ -39,7 +39,7 @@ public: status_t RegisterCallback(Callback* callback); status_t UnregisterCallback(Callback* callback); - inline ServerAddress LocalID(); + inline PeerAddress LocalID(); protected: status_t StartServer(); @@ -72,10 +72,10 @@ private: }; -inline ServerAddress +inline PeerAddress CallbackServer::LocalID() { - ServerAddress address; + PeerAddress address; fListener->GetLocalAddress(&address); return address; } diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp b/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp index 70876f6682..c07b20e21e 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp @@ -73,7 +73,7 @@ RequestManager::FindRequest(uint32 xid) } -Server::Server(Connection* connection, ServerAddress* address) +Server::Server(Connection* connection, PeerAddress* address) : fConnection(connection), fAddress(address), @@ -301,7 +301,7 @@ ServerManager::~ServerManager() status_t -ServerManager::Acquire(Server** _server, const ServerAddress& address, +ServerManager::Acquire(Server** _server, const PeerAddress& address, ProgramData* (*createPrivateData)(Server*)) { status_t result; @@ -372,7 +372,7 @@ ServerManager::Release(Server* server) ServerNode* -ServerManager::_Find(const ServerAddress& address) +ServerManager::_Find(const PeerAddress& address) { ServerNode* node = fRoot; while (node != NULL) { diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCServer.h b/src/add-ons/kernel/file_systems/nfs4/RPCServer.h index f4afd7f02e..5ba84ec5c8 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RPCServer.h +++ b/src/add-ons/kernel/file_systems/nfs4/RPCServer.h @@ -57,7 +57,7 @@ public: class Server { public: Server(Connection* connection, - ServerAddress* address); + PeerAddress* address); virtual ~Server(); status_t SendCall(Call* call, Reply** reply); @@ -74,8 +74,8 @@ public: status_t Repair(); - inline const ServerAddress& ID() const; - inline ServerAddress LocalID() const; + inline const PeerAddress& ID() const; + inline PeerAddress LocalID() const; inline ProgramData* PrivateData(); inline void SetPrivateData(ProgramData* privateData); @@ -96,7 +96,7 @@ private: RequestManager fRequests; Connection* fConnection; - const ServerAddress* fAddress; + const PeerAddress* fAddress; ProgramData* fPrivateData; @@ -125,17 +125,17 @@ Server::CancelCall(Request* request) } -inline const ServerAddress& +inline const PeerAddress& Server::ID() const { return *fAddress; } -inline ServerAddress +inline PeerAddress Server::LocalID() const { - ServerAddress addr; + PeerAddress addr; memset(&addr, 0, sizeof(addr)); fConnection->GetLocalAddress(&addr); return addr; @@ -158,7 +158,7 @@ Server::SetPrivateData(ProgramData* privateData) struct ServerNode { - ServerAddress fID; + PeerAddress fID; Server* fServer; int fRefCount; @@ -171,13 +171,13 @@ public: ServerManager(); ~ServerManager(); - status_t Acquire(Server** _server, const ServerAddress& address, + status_t Acquire(Server** _server, const PeerAddress& address, ProgramData* (*createPrivateData)(Server*)); void Release(Server* server); private: - ServerNode* _Find(const ServerAddress& address); + ServerNode* _Find(const PeerAddress& address); void _Delete(ServerNode* node); ServerNode* _Insert(ServerNode* node); diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp index 3eab8254b7..306e680aa8 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp @@ -673,8 +673,8 @@ RequestBuilder::SetClientID(RPC::Server* server) uint32 id = server->GetCallback()->ID(); - ServerAddress local = gRPCCallbackServer->LocalID(); - ServerAddress servAddr = server->LocalID(); + PeerAddress local = gRPCCallbackServer->LocalID(); + PeerAddress servAddr = server->LocalID(); servAddr.SetPort(local.Port()); fRequest->Stream().AddString(local.ProtocolString()); @@ -700,46 +700,15 @@ RequestBuilder::_GenerateClientId(XDR::WriteStream& stream, char id[512] = "HAIKU:kernel:"; int pos = strlen(id); - const sockaddr* remoteAddress = - reinterpret_cast(&server->ID().fAddress); + PeerAddress local = server->LocalID(); - ServerAddress local = server->LocalID(); - const sockaddr* localAddress = reinterpret_cast(&local.fAddress); - - const sockaddr_in* address4; - const sockaddr_in6* address6; - switch (remoteAddress->sa_family) { - case AF_INET: - address4 = reinterpret_cast(remoteAddress); + memcpy(id + pos, server->ID().InAddr(), server->ID().InAddrSize()); + pos += sizeof(server->ID().InAddrSize()); - memcpy(id + pos, &address4->sin_addr, sizeof(address4->sin_addr)); - pos += sizeof(address4->sin_addr); + memcpy(id + pos, local.InAddr(), local.InAddrSize()); + pos += sizeof(local.InAddrSize()); - memcpy(id + pos, - &reinterpret_cast(localAddress)->sin_addr, - sizeof(address4->sin_addr)); - pos += sizeof(address4->sin_addr); - - *(uint16*)(id + pos) = address4->sin_port; - break; - - case AF_INET6: - address6 = reinterpret_cast(remoteAddress); - - memcpy(id + pos, &address6->sin6_addr, sizeof(address6->sin6_addr)); - pos += sizeof(address6->sin6_addr); - - memcpy(id + pos, - &reinterpret_cast(localAddress)->sin6_addr, - sizeof(address6->sin6_addr)); - pos += sizeof(address6->sin6_addr); - - *(uint16*)(id + pos) = address6->sin6_port; - break; - - default: - return B_BAD_VALUE; - } + *(uint16*)(id + pos) = server->ID().Port(); pos += sizeof(uint16); *(uint16*)(id + pos) = server->ID().fProtocol; 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 e2483320c0..f40cc40f2e 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -45,7 +45,7 @@ CreateNFS4Server(RPC::Server* serv) // TODO: IPv6 address will cause problems static status_t -ParseArguments(const char* _args, ServerAddress* address, char* _path) +ParseArguments(const char* _args, PeerAddress* address, char* _path) { if (_args == NULL) return B_BAD_VALUE; @@ -58,7 +58,7 @@ ParseArguments(const char* _args, ServerAddress* address, char* _path) } *path++ = '\0'; - status_t result = ServerAddress::ResolveName(args, address); + status_t result = PeerAddress::ResolveName(args, address); if (result != B_OK) return result; @@ -82,7 +82,7 @@ nfs4_mount(fs_volume* volume, const char* device, uint32 flags, return B_NO_MEMORY; locker.Unlock(); - ServerAddress address; + PeerAddress address; char path[256]; result = ParseArguments(args, &address, path); if (result != B_OK) From a15e8fcfbe194df5cac40bea7bfb1f8750aeadd2 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Thu, 16 Aug 2012 03:06:36 +0200 Subject: [PATCH 198/252] nfs4: Check for semaphore creation errors in ConnectionBase classes --- .../file_systems/nfs4/CacheRevalidator.cpp | 6 +++-- .../kernel/file_systems/nfs4/Connection.cpp | 25 ++++++++++++++++++- .../kernel/file_systems/nfs4/NFS4Object.cpp | 14 ++++++++--- .../kernel/file_systems/nfs4/NFS4Server.cpp | 3 ++- .../kernel/file_systems/nfs4/RPCServer.cpp | 2 +- 5 files changed, 41 insertions(+), 9 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/CacheRevalidator.cpp b/src/add-ons/kernel/file_systems/nfs4/CacheRevalidator.cpp index 6c5e05dadc..749d6f8d57 100644 --- a/src/add-ons/kernel/file_systems/nfs4/CacheRevalidator.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/CacheRevalidator.cpp @@ -79,7 +79,8 @@ CacheRevalidator::_DirectoryCacheRevalidator() B_RELATIVE_TIMEOUT, DirectoryCache::kExpirationTime); if (result != B_TIMED_OUT) { - release_sem(fWaitCancel); + if (result == B_OK) + release_sem(fWaitCancel); return; } continue; @@ -95,7 +96,8 @@ CacheRevalidator::_DirectoryCacheRevalidator() status_t result = acquire_sem_etc(fWaitCancel, 1, B_ABSOLUTE_TIMEOUT, current->ExpireTime()); if (result != B_TIMED_OUT) { - release_sem(fWaitCancel); + if (result == B_OK) + release_sem(fWaitCancel); return; } diff --git a/src/add-ons/kernel/file_systems/nfs4/Connection.cpp b/src/add-ons/kernel/file_systems/nfs4/Connection.cpp index 34d370d94e..22f08f27e1 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Connection.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Connection.cpp @@ -476,7 +476,14 @@ Connection::Connect(Connection **_connection, const PeerAddress& address) if (conn == NULL) return B_NO_MEMORY; - status_t result = conn->Connect(); + status_t result; + if (conn->fWaitCancel < B_OK) { + result = conn->fWaitCancel; + delete conn; + return result; + } + + result = conn->Connect(); if (result != B_OK) { delete conn; return result; @@ -495,6 +502,14 @@ Connection::SetTo(Connection **_connection, int socket, Connection* conn = CreateObject(address); if (conn == NULL) return B_NO_MEMORY; + + status_t result; + if (conn->fWaitCancel < B_OK) { + result = conn->fWaitCancel; + delete conn; + return result; + } + conn->fSocket = socket; *_connection = conn; @@ -642,6 +657,14 @@ ConnectionListener::Listen(ConnectionListener** listener, uint16 port) return B_NO_MEMORY; } + status_t result; + if ((*listener)->fWaitCancel < B_OK) { + result = (*listener)->fWaitCancel; + close(sock); + delete *listener; + return result; + } + (*listener)->fSocket = sock; return B_OK; diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp index e29379d825..0e089acd2f 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp @@ -41,7 +41,9 @@ NFS4Object::HandleErrors(uint32 nfs4Error, RPC::Server* serv, *sequence = fFileSystem->OpenOwnerSequenceLock(); return true; - } else if ((cookie->fMode & O_NONBLOCK) == 0) { + } + + if ((cookie->fMode & O_NONBLOCK) == 0) { status_t result = acquire_sem_etc(cookie->fSnoozeCancel, 1, B_RELATIVE_TIMEOUT, sSecToBigTime(5)); @@ -49,7 +51,8 @@ NFS4Object::HandleErrors(uint32 nfs4Error, RPC::Server* serv, *sequence = fFileSystem->OpenOwnerSequenceLock(); if (result != B_TIMED_OUT) { - release_sem(cookie->fSnoozeCancel); + if (result == B_OK) + release_sem(cookie->fSnoozeCancel); return false; } return true; @@ -71,7 +74,9 @@ NFS4Object::HandleErrors(uint32 nfs4Error, RPC::Server* serv, if (sequence != NULL) *sequence = fFileSystem->OpenOwnerSequenceLock(); return true; - } else if ((cookie->fMode & O_NONBLOCK) == 0) { + } + + if ((cookie->fMode & O_NONBLOCK) == 0) { status_t result = acquire_sem_etc(cookie->fSnoozeCancel, 1, B_RELATIVE_TIMEOUT, sSecToBigTime(leaseTime) / 3); @@ -79,7 +84,8 @@ NFS4Object::HandleErrors(uint32 nfs4Error, RPC::Server* serv, *sequence = fFileSystem->OpenOwnerSequenceLock(); if (result != B_TIMED_OUT) { - release_sem(cookie->fSnoozeCancel); + if (result == B_OK) + release_sem(cookie->fSnoozeCancel); return false; } return true; diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp index 173e527596..60a6ee0d13 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp @@ -231,7 +231,8 @@ NFS4Server::_Renewal() status_t result = acquire_sem_etc(fWaitCancel, 1, B_RELATIVE_TIMEOUT, sSecToBigTime(fLeaseTime - 2)); if (result != B_TIMED_OUT) { - release_sem(fWaitCancel); + if (result == B_OK) + release_sem(fWaitCancel); return B_OK; } diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp b/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp index c07b20e21e..4095d4111a 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp @@ -112,7 +112,7 @@ Server::_StartListening() fThreadCancel = false; fThreadError = B_OK; fThread = spawn_kernel_thread(&Server::_ListenerThreadStart, - "NFSv4 Listener", B_NORMAL_PRIORITY, this); + "NFSv4 Listener", B_NORMAL_PRIORITY, this); if (fThread < B_OK) return fThread; From 870528b79923b065c9d04bc598b43a518f3cfafa Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Thu, 16 Aug 2012 03:41:29 +0200 Subject: [PATCH 199/252] nfs4: Fix gcc4 warnings --- headers/private/net/dns_resolver.h | 10 +++++++--- src/add-ons/kernel/file_systems/nfs4/Cookie.cpp | 3 ++- src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp | 4 ++-- src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp | 3 ++- src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp | 4 ++-- .../kernel/file_systems/nfs4/ReplyInterpreter.cpp | 6 +++--- 6 files changed, 18 insertions(+), 12 deletions(-) diff --git a/headers/private/net/dns_resolver.h b/headers/private/net/dns_resolver.h index 0a5cf14525..d868ca0381 100644 --- a/headers/private/net/dns_resolver.h +++ b/headers/private/net/dns_resolver.h @@ -26,8 +26,8 @@ struct dns_resolver_module { static inline int -getaddrinfo(const char* node, const char* service, const struct addrinfo* hints, - struct addrinfo** res) +kgetaddrinfo(const char* node, const char* service, + const struct addrinfo* hints, struct addrinfo** res) { dns_resolver_module* dns; status_t result = get_module(DNS_RESOLVER_MODULE_NAME, @@ -44,11 +44,15 @@ getaddrinfo(const char* node, const char* service, const struct addrinfo* hints, static inline void -freeaddrinfo(struct addrinfo* res) +kfreeaddrinfo(struct addrinfo* res) { free(res); } +#define getaddrinfo kgetaddrinfo +#define freeaddrinfo kfreeaddrinfo + + #endif // DNS_RESOLVER_H diff --git a/src/add-ons/kernel/file_systems/nfs4/Cookie.cpp b/src/add-ons/kernel/file_systems/nfs4/Cookie.cpp index 23a38e2950..805721a153 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Cookie.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Cookie.cpp @@ -53,7 +53,8 @@ LockInfo::operator==(const struct flock& lock) const uint64 start = static_cast(lock.l_start); uint64 len = static_cast(lock.l_len); - return fStart == start && fLength == len || eof && fLength == UINT64_MAX; + return fStart == start && (fLength == len + || (eof && fLength == UINT64_MAX)); } diff --git a/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp b/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp index 2adf0b7f4d..46bd002dc8 100644 --- a/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp @@ -110,8 +110,8 @@ FileSystem::Mount(FileSystem** pfs, RPC::Server* serv, const char* fsPath, result = reply.Access(NULL, &allowed); if (result != B_OK) return result; - else if (allowed & (ACCESS4_READ | ACCESS4_LOOKUP) - != (ACCESS4_READ | ACCESS4_LOOKUP)) + else if ((allowed & (ACCESS4_READ | ACCESS4_LOOKUP)) + != (ACCESS4_READ | ACCESS4_LOOKUP)) return B_PERMISSION_DENIED; AttrValue* values; diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp index 145c50f842..81e6280867 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp @@ -938,7 +938,8 @@ NFS4Inode::ReadDirOnce(DirEntry** dirents, uint32* count, OpenDirCookie* cookie, return result; } - if (*change == 0 && before[0].fData.fValue64 == after[0].fData.fValue64 + if ((*change == 0 + && before[0].fData.fValue64 == after[0].fData.fValue64) || *change == after[0].fData.fValue64) *change = after[0].fData.fValue64; else diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp index 60a6ee0d13..1b09e633a7 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp @@ -109,8 +109,8 @@ uint64 NFS4Server::ClientId(uint64 prevId, bool forceNew) { MutexLocker _(fClientIdLock); - if (fUseCount == 0 && fClientIdLastUse + (time_t)LeaseTime() < time(NULL) - || forceNew && fClientId == prevId) { + if ((fUseCount == 0 && fClientIdLastUse + (time_t)LeaseTime() < time(NULL)) + || (forceNew && fClientId == prevId)) { Request request(fServer); request.Builder().SetClientID(fServer); diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp index 6f04552ab0..bf4f4dd2ac 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp @@ -161,11 +161,11 @@ ReplyInterpreter::Create(uint64* before, uint64* after, bool& atomic) // Bit Twiddling Hacks // http://graphics.stanford.edu/~seander/bithacks.html -static inline uint32 sCountBits(uint32 v) +static inline uint32 CountBits(uint32 v) { v = v - ((v >> 1) & 0x55555555); v = (v & 0x33333333) + ((v >> 2) & 0x33333333); - return ((v + (v >> 4) & 0xF0F0F0F) * 0x1010101) >> 24; + return (((v + (v >> 4)) & 0xF0F0F0F) * 0x1010101) >> 24; } @@ -562,7 +562,7 @@ ReplyInterpreter::_DecodeAttrs(XDR::ReadStream& str, AttrValue** attrs, uint32 attr_count = 0; for (uint32 i = 0; i < bcount; i++) { bitmap[i] = str.GetUInt(); - attr_count += sCountBits(bitmap[i]); + attr_count += CountBits(bitmap[i]); } if (attr_count == 0) { From 060a4636e4a286dd70b9cbf335d12ddc10924937 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Thu, 16 Aug 2012 19:59:50 +0200 Subject: [PATCH 200/252] nfs4: Make the client more configurable --- .../file_systems/nfs4/CacheRevalidator.cpp | 1 + .../file_systems/nfs4/CacheRevalidator.h | 5 +- .../kernel/file_systems/nfs4/Connection.cpp | 10 +++ .../kernel/file_systems/nfs4/Connection.h | 2 + .../kernel/file_systems/nfs4/Delegation.cpp | 2 +- .../file_systems/nfs4/DirectoryCache.cpp | 12 ++- .../kernel/file_systems/nfs4/DirectoryCache.h | 2 + .../kernel/file_systems/nfs4/FileInfo.cpp | 2 +- .../kernel/file_systems/nfs4/FileSystem.cpp | 28 +++--- .../kernel/file_systems/nfs4/FileSystem.h | 24 +++++- .../kernel/file_systems/nfs4/Inode.cpp | 2 +- .../kernel/file_systems/nfs4/InodeDir.cpp | 55 +++++++----- .../file_systems/nfs4/MetadataCache.cpp | 8 +- .../kernel/file_systems/nfs4/NFS4Inode.cpp | 42 ++++----- .../kernel/file_systems/nfs4/NFS4Object.cpp | 3 +- .../kernel/file_systems/nfs4/NFS4Object.h | 10 +++ .../kernel/file_systems/nfs4/NFS4Server.cpp | 6 +- .../kernel/file_systems/nfs4/OpenState.cpp | 8 +- .../kernel/file_systems/nfs4/Request.cpp | 24 +++++- .../kernel/file_systems/nfs4/Request.h | 12 +-- .../kernel/file_systems/nfs4/RootInode.cpp | 18 ++-- .../file_systems/nfs4/kernel_interface.cpp | 86 ++++++++++++++----- 22 files changed, 251 insertions(+), 111 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/CacheRevalidator.cpp b/src/add-ons/kernel/file_systems/nfs4/CacheRevalidator.cpp index 749d6f8d57..d1abbbf4e6 100644 --- a/src/add-ons/kernel/file_systems/nfs4/CacheRevalidator.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/CacheRevalidator.cpp @@ -105,6 +105,7 @@ CacheRevalidator::_DirectoryCacheRevalidator() } fDirectoryCaches.RemoveHead(); + current->fRevalidated = false; if (current->Revalidate() == B_OK) AddDirectory(current); diff --git a/src/add-ons/kernel/file_systems/nfs4/CacheRevalidator.h b/src/add-ons/kernel/file_systems/nfs4/CacheRevalidator.h index b3bfed9541..7e1e4a7862 100644 --- a/src/add-ons/kernel/file_systems/nfs4/CacheRevalidator.h +++ b/src/add-ons/kernel/file_systems/nfs4/CacheRevalidator.h @@ -58,6 +58,7 @@ CacheRevalidator::Unlock() inline void CacheRevalidator::AddDirectory(DirectoryCache* cache) { + cache->fRevalidated = true; fDirectoryCaches.InsertAfter(fDirectoryCaches.Tail(), cache); } @@ -65,7 +66,9 @@ CacheRevalidator::AddDirectory(DirectoryCache* cache) inline void CacheRevalidator::RemoveDirectory(DirectoryCache* cache) { - fDirectoryCaches.Remove(cache); + if (cache->fRevalidated == true) + fDirectoryCaches.Remove(cache); + cache->fRevalidated = false; } diff --git a/src/add-ons/kernel/file_systems/nfs4/Connection.cpp b/src/add-ons/kernel/file_systems/nfs4/Connection.cpp index 22f08f27e1..d94801b2b0 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Connection.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Connection.cpp @@ -77,6 +77,16 @@ PeerAddress::ProtocolString() const } +void +PeerAddress::SetProtocol(const char* protocol) +{ + if (strcmp(protocol, "tcp") == 0) + fProtocol = IPPROTO_TCP; + else if (strcmp(protocol, "udp") == 0) + fProtocol = IPPROTO_UDP; +} + + char* PeerAddress::UniversalAddress() const { diff --git a/src/add-ons/kernel/file_systems/nfs4/Connection.h b/src/add-ons/kernel/file_systems/nfs4/Connection.h index b10cc9c2d7..aceb2c0742 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Connection.h +++ b/src/add-ons/kernel/file_systems/nfs4/Connection.h @@ -27,6 +27,8 @@ struct PeerAddress { PeerAddress(); const char* ProtocolString() const; + void SetProtocol(const char* protocol); + char* UniversalAddress() const; socklen_t AddressSize() const; diff --git a/src/add-ons/kernel/file_systems/nfs4/Delegation.cpp b/src/add-ons/kernel/file_systems/nfs4/Delegation.cpp index a0ce499edb..bf2b33a11f 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Delegation.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Delegation.cpp @@ -41,7 +41,7 @@ Delegation::ReturnDelegation() { do { RPC::Server* serv = fFileSystem->Server(); - Request request(serv); + Request request(serv, fFileSystem); RequestBuilder& req = request.Builder(); req.PutFH(fInfo.fHandle); diff --git a/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.cpp b/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.cpp index b9483a0c07..52be9fddff 100644 --- a/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.cpp @@ -49,6 +49,7 @@ DirectoryCacheSnapshot::~DirectoryCacheSnapshot() DirectoryCache::DirectoryCache(Inode* inode, bool attr) : + fRevalidated(false), fDirectoryCache(NULL), fInode(inode), fAttrDir(attr), @@ -60,6 +61,10 @@ DirectoryCache::DirectoryCache(Inode* inode, bool attr) DirectoryCache::~DirectoryCache() { + fInode->GetFileSystem()->Revalidator().Lock(); + fInode->GetFileSystem()->Revalidator().RemoveDirectory(this); + fInode->GetFileSystem()->Revalidator().Unlock(); + mutex_destroy(&fLock); } @@ -179,7 +184,12 @@ status_t DirectoryCache::Revalidate() { uint64 change; - if (fInode->GetChangeInfo(&change, true) == B_OK && change == fChange) { + if (fInode->GetChangeInfo(&change, true) != B_OK) { + Trash(); + return B_ERROR; + } + + if (change == fChange) { fExpireTime = system_time() + kExpirationTime; return B_OK; } diff --git a/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.h b/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.h index ac152f0158..4099950833 100644 --- a/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.h +++ b/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.h @@ -65,6 +65,8 @@ public: inline time_t ExpireTime(); static const bigtime_t kExpirationTime = 15000000; + + bool fRevalidated; protected: void NotifyChanges(DirectoryCacheSnapshot* oldSnapshot, DirectoryCacheSnapshot* newSnapshot); diff --git a/src/add-ons/kernel/file_systems/nfs4/FileInfo.cpp b/src/add-ons/kernel/file_systems/nfs4/FileInfo.cpp index 402c642356..e81242e526 100644 --- a/src/add-ons/kernel/file_systems/nfs4/FileInfo.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/FileInfo.cpp @@ -49,7 +49,7 @@ FileInfo::ParsePath(RequestBuilder& req, uint32& count, const char* _path) status_t FileInfo::UpdateFileHandles(FileSystem* fs) { - Request request(fs->Server()); + Request request(fs->Server(), fs); RequestBuilder& req = request.Builder(); req.PutRootFH(); diff --git a/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp b/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp index 46bd002dc8..4c8963aa9e 100644 --- a/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp @@ -11,6 +11,7 @@ #include +#include #include #include "Request.h" @@ -21,7 +22,7 @@ extern RPC::ServerManager* gRPCServerManager; extern RPC::ProgramData* CreateNFS4Server(RPC::Server* serv); -FileSystem::FileSystem() +FileSystem::FileSystem(const MountConfiguration& configuration) : fNext(NULL), fPrev(NULL), @@ -30,7 +31,8 @@ FileSystem::FileSystem() fNamedAttrs(true), fPath(NULL), fRoot(NULL), - fId(1) + fId(1), + fConfiguration(configuration) { fOpenOwner = rand(); fOpenOwner <<= 32; @@ -73,9 +75,14 @@ sGetPath(const char* root, const char* path) status_t FileSystem::Mount(FileSystem** pfs, RPC::Server* serv, const char* fsPath, - dev_t id) + dev_t id, const MountConfiguration& configuration) { - Request request(serv); + FileSystem* fs = new(std::nothrow) FileSystem(configuration); + if (fs == NULL) + return B_NO_MEMORY; + ObjectDeleter fsDeleter(fs); + + Request request(serv, fs); RequestBuilder& req = request.Builder(); req.PutRootFH(); @@ -120,10 +127,6 @@ FileSystem::Mount(FileSystem** pfs, RPC::Server* serv, const char* fsPath, if (result != B_OK || count < 2) return result; - FileSystem* fs = new(std::nothrow) FileSystem; - if (fs == NULL) - return B_NO_MEMORY; - // FATTR4_SUPPORTED_ATTRS is mandatory memcpy(fs->fSupAttrs, &values[0].fData.fValue64, sizeof(fs->fSupAttrs)); @@ -163,23 +166,20 @@ FileSystem::Mount(FileSystem** pfs, RPC::Server* serv, const char* fsPath, delete[] values; - if (fi.fName == NULL || fi.fPath == NULL) { - delete fs; + if (fi.fName == NULL || fi.fPath == NULL) return B_NO_MEMORY; - } Inode* inode; result = Inode::CreateInode(fs, fi, &inode); - if (result != B_OK) { - delete fs; + if (result != B_OK) return result; - } fs->fRoot = reinterpret_cast(inode); fs->NFSServer()->AddFileSystem(fs); *pfs = fs; + fsDeleter.Detach(); return B_OK; } diff --git a/src/add-ons/kernel/file_systems/nfs4/FileSystem.h b/src/add-ons/kernel/file_systems/nfs4/FileSystem.h index 3a2dfaceea..e7884fed41 100644 --- a/src/add-ons/kernel/file_systems/nfs4/FileSystem.h +++ b/src/add-ons/kernel/file_systems/nfs4/FileSystem.h @@ -19,10 +19,19 @@ class Inode; class RootInode; +struct MountConfiguration { + bool fHard; + int fRetryLimit; + + bool fEmulateNamedAttrs; + bool fCacheMetadata; +}; + class FileSystem { public: static status_t Mount(FileSystem** pfs, RPC::Server* serv, - const char* path, dev_t id); + const char* path, dev_t id, + const MountConfiguration& configuration); ~FileSystem(); status_t GetInode(ino_t id, Inode** inode); @@ -65,10 +74,12 @@ public: inline bool NamedAttrs(); inline void SetNamedAttrs(bool attrs); + inline const MountConfiguration& GetConfiguration(); + FileSystem* fNext; FileSystem* fPrev; private: - FileSystem(); + FileSystem(const MountConfiguration& config); CacheRevalidator fCacheRevalidator; @@ -99,6 +110,8 @@ private: dev_t fDevId; InodeIdMap fInoIdMap; + + MountConfiguration fConfiguration; }; @@ -223,5 +236,12 @@ FileSystem::SetNamedAttrs(bool attrs) } +inline const MountConfiguration& +FileSystem::GetConfiguration() +{ + return fConfiguration; +} + + #endif // FILESYSTEM_H diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index 02ea63e224..c8cfd2c808 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -55,7 +55,7 @@ Inode::CreateInode(FileSystem* fs, const FileInfo &fi, Inode** _inode) uint64 size; do { RPC::Server* serv = fs->Server(); - Request request(serv); + Request request(serv, fs); RequestBuilder& req = request.Builder(); req.PutFH(inode->fInfo.fHandle); diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp b/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp index 33e782251c..65f735aa79 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp @@ -67,32 +67,43 @@ Inode::LoadAttrDirHandle() FileHandle handle; status_t result; - if (!fFileSystem->NamedAttrs()) { - char* attrDir - = reinterpret_cast(malloc(strlen(fInfo.fName) + 32)); - if (attrDir == NULL) - return B_NO_MEMORY; - strcpy(attrDir, "."); - strcat(attrDir, fInfo.fName); - strcat(attrDir, "-haiku-attrs"); - result = NFS4Inode::LookUp(attrDir, NULL, NULL, &handle, true); - if (result == B_ENTRY_NOT_FOUND) { - ChangeInfo change; - struct stat st; - Stat(&st); - st.st_mode |= S_IXUSR | S_IXGRP | S_IXOTH; - result = NFS4Inode::CreateObject(attrDir, NULL, st.st_mode, NF4DIR, - &change, NULL, &handle, true); + if (fFileSystem->NamedAttrs()) { + result = NFS4Inode::OpenAttrDir(&handle); + if (result == B_OK) { + fInfo.fAttrDir = handle; + return B_OK; } - free(attrDir); - } else { - result = NFS4Inode::OpenAttrDir(&handle); - if (result == B_UNSUPPORTED) - fFileSystem->SetNamedAttrs(false); + if (result != B_UNSUPPORTED) + return result; + + fFileSystem->SetNamedAttrs(false); } + if (!fFileSystem->GetConfiguration().fEmulateNamedAttrs) + return B_UNSUPPORTED; + + char* attrDir + = reinterpret_cast(malloc(strlen(fInfo.fName) + 32)); + if (attrDir == NULL) + return B_NO_MEMORY; + strcpy(attrDir, "."); + strcat(attrDir, fInfo.fName); + strcat(attrDir, "-haiku-attrs"); + + result = NFS4Inode::LookUp(attrDir, NULL, NULL, &handle, true); + if (result == B_ENTRY_NOT_FOUND) { + ChangeInfo change; + struct stat st; + Stat(&st); + st.st_mode |= S_IXUSR | S_IXGRP | S_IXOTH; + result = NFS4Inode::CreateObject(attrDir, NULL, st.st_mode, NF4DIR, + &change, NULL, &handle, true); + } + + free(attrDir); + if (result != B_OK) return result; @@ -128,7 +139,7 @@ Inode::ReadDirUp(struct dirent* de, uint32 pos, uint32 size) { do { RPC::Server* serv = fFileSystem->Server(); - Request request(serv); + Request request(serv, fFileSystem); RequestBuilder& req = request.Builder(); req.PutFH(fInfo.fHandle); diff --git a/src/add-ons/kernel/file_systems/nfs4/MetadataCache.cpp b/src/add-ons/kernel/file_systems/nfs4/MetadataCache.cpp index 3c0f9b6008..bc345a9401 100644 --- a/src/add-ons/kernel/file_systems/nfs4/MetadataCache.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/MetadataCache.cpp @@ -35,7 +35,8 @@ status_t MetadataCache::GetStat(struct stat* st) { MutexLocker _(fLock); - if (fForceValid || fExpire > time(NULL)) { + bool cache = fInode->GetFileSystem()->GetConfiguration().fCacheMetadata; + if (fForceValid || (cache && fExpire > time(NULL))) { // Do not touch other members of struct stat st->st_size = fStatCache.st_size; st->st_mode = fStatCache.st_mode; @@ -110,7 +111,10 @@ MetadataCache::SetAccess(uid_t uid, uint32 allowed) entry.fAllowed = allowed; entry.fExpire = time(NULL) + kExpirationTime; entry.fForceValid = fForceValid; - fAccessCache.Insert(uid, entry); + + bool cache = fInode->GetFileSystem()->GetConfiguration().fCacheMetadata; + if (fForceValid || cache) + fAccessCache.Insert(uid, entry); } diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp index 81e6280867..43ae3fe060 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp @@ -18,7 +18,7 @@ NFS4Inode::GetChangeInfo(uint64* change, bool attrDir) { do { RPC::Server* serv = fFileSystem->Server(); - Request request(serv); + Request request(serv, fFileSystem); RequestBuilder& req = request.Builder(); if (attrDir) @@ -60,7 +60,7 @@ NFS4Inode::CommitWrites() { do { RPC::Server* serv = fFileSystem->Server(); - Request request(serv); + Request request(serv, fFileSystem); RequestBuilder& req = request.Builder(); req.PutFH(fInfo.fHandle); @@ -86,7 +86,7 @@ NFS4Inode::Access(uint32* allowed) { do { RPC::Server* serv = fFileSystem->Server(); - Request request(serv); + Request request(serv, fFileSystem); RequestBuilder& req = request.Builder(); req.PutFH(fInfo.fHandle); @@ -114,7 +114,7 @@ NFS4Inode::LookUp(const char* name, uint64* change, uint64* fileID, { do { RPC::Server* serv = fFileSystem->Server(); - Request request(serv); + Request request(serv, fFileSystem); RequestBuilder& req = request.Builder(); if (parent) @@ -199,7 +199,7 @@ NFS4Inode::Link(Inode* dir, const char* name, ChangeInfo* changeInfo) { do { RPC::Server* serv = fFileSystem->Server(); - Request request(serv); + Request request(serv, fFileSystem); RequestBuilder& req = request.Builder(); req.PutFH(fInfo.fHandle); @@ -231,7 +231,7 @@ NFS4Inode::ReadLink(void* buffer, size_t* length) { do { RPC::Server* serv = fFileSystem->Server(); - Request request(serv); + Request request(serv, fFileSystem); RequestBuilder& req = request.Builder(); req.PutFH(fInfo.fHandle); @@ -262,7 +262,7 @@ NFS4Inode::GetStat(AttrValue** values, uint32* count, OpenAttrCookie* cookie) { do { RPC::Server* serv = fFileSystem->Server(); - Request request(serv); + Request request(serv, fFileSystem); RequestBuilder& req = request.Builder(); if (cookie != NULL) @@ -297,7 +297,7 @@ NFS4Inode::WriteStat(OpenState* state, AttrValue* attrs, uint32 attrCount) { do { RPC::Server* serv = fFileSystem->Server(); - Request request(serv); + Request request(serv, fFileSystem); RequestBuilder& req = request.Builder(); if (state != NULL) { @@ -335,7 +335,7 @@ NFS4Inode::Rename(Inode* from, Inode* to, const char* fromName, { do { RPC::Server* serv = from->fFileSystem->Server(); - Request request(serv); + Request request(serv, from->fFileSystem); RequestBuilder& req = request.Builder(); if (attribute) @@ -421,7 +421,7 @@ NFS4Inode::CreateFile(const char* name, int mode, int perms, OpenState* state, state->fClientID = fFileSystem->NFSServer()->ClientId(); RPC::Server* serv = fFileSystem->Server(); - Request request(serv); + Request request(serv, fFileSystem); RequestBuilder& req = request.Builder(); req.PutFH(fInfo.fHandle); @@ -512,7 +512,7 @@ NFS4Inode::OpenFile(OpenState* state, int mode, OpenDelegationData* delegation) state->fClientID = fFileSystem->NFSServer()->ClientId(); RPC::Server* serv = fFileSystem->Server(); - Request request(serv); + Request request(serv, fFileSystem); RequestBuilder& req = request.Builder(); // Since we are opening the file using a pair (parentFH, name) we @@ -613,7 +613,7 @@ NFS4Inode::OpenAttr(OpenState* state, const char* name, int mode, state->fClientID = fFileSystem->NFSServer()->ClientId(); RPC::Server* serv = fFileSystem->Server(); - Request request(serv); + Request request(serv, fFileSystem); RequestBuilder& req = request.Builder(); req.PutFH(fInfo.fAttrDir); @@ -665,7 +665,7 @@ NFS4Inode::ReadFile(OpenStateCookie* cookie, OpenState* state, uint64 position, { do { RPC::Server* serv = fFileSystem->Server(); - Request request(serv); + Request request(serv, fFileSystem); RequestBuilder& req = request.Builder(); req.PutFH(state->fInfo.fHandle); @@ -697,7 +697,7 @@ NFS4Inode::WriteFile(OpenStateCookie* cookie, OpenState* state, uint64 position, do { RPC::Server* serv = fFileSystem->Server(); - Request request(serv); + Request request(serv, fFileSystem); RequestBuilder& req = request.Builder(); req.PutFH(state->fInfo.fHandle); @@ -732,7 +732,7 @@ NFS4Inode::CreateObject(const char* name, const char* path, int mode, { do { RPC::Server* serv = fFileSystem->Server(); - Request request(serv); + Request request(serv, fFileSystem); RequestBuilder& req = request.Builder(); if (parent) @@ -810,7 +810,7 @@ NFS4Inode::RemoveObject(const char* name, FileType type, ChangeInfo* changeInfo, { do { RPC::Server* serv = fFileSystem->Server(); - Request request(serv); + Request request(serv, fFileSystem); RequestBuilder& req = request.Builder(); req.PutFH(fInfo.fHandle); @@ -888,7 +888,7 @@ NFS4Inode::ReadDirOnce(DirEntry** dirents, uint32* count, OpenDirCookie* cookie, { do { RPC::Server* serv = fFileSystem->Server(); - Request request(serv); + Request request(serv, fFileSystem); RequestBuilder& req = request.Builder(); if (attribute) @@ -958,7 +958,7 @@ NFS4Inode::OpenAttrDir(FileHandle* handle) { do { RPC::Server* serv = fFileSystem->Server(); - Request request(serv); + Request request(serv, fFileSystem); RequestBuilder& req = request.Builder(); req.PutFH(fInfo.fHandle); @@ -990,7 +990,7 @@ NFS4Inode::TestLock(OpenFileCookie* cookie, LockType* type, uint64* position, { do { RPC::Server* serv = fFileSystem->Server(); - Request request(serv); + Request request(serv, fFileSystem); RequestBuilder& req = request.Builder(); req.PutFH(fInfo.fHandle); @@ -1027,7 +1027,7 @@ NFS4Inode::AcquireLock(OpenFileCookie* cookie, LockInfo* lockInfo, bool wait) MutexLocker ownerLocker(lockInfo->fOwner->fLock); RPC::Server* serv = fFileSystem->Server(); - Request request(serv); + Request request(serv, fFileSystem); RequestBuilder& req = request.Builder(); req.PutFH(fInfo.fHandle); @@ -1073,7 +1073,7 @@ NFS4Inode::ReleaseLock(OpenFileCookie* cookie, LockInfo* lockInfo) MutexLocker ownerLocker(lockInfo->fOwner->fLock); RPC::Server* serv = fFileSystem->Server(); - Request request(serv); + Request request(serv, fFileSystem); RequestBuilder& req = request.Builder(); req.PutFH(fInfo.fHandle); diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp index 0e089acd2f..e24abcecd0 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp @@ -111,6 +111,7 @@ NFS4Object::HandleErrors(uint32 nfs4Error, RPC::Server* serv, return false; // FileHandle has expired or is invalid + case NFS4ERR_NOFILEHANDLE: case NFS4ERR_BADHANDLE: case NFS4ERR_FHEXPIRED: if (fInfo.UpdateFileHandles(fFileSystem) == B_OK) @@ -143,7 +144,7 @@ NFS4Object::ConfirmOpen(const FileHandle& fh, OpenState* state, { do { RPC::Server* serv = fFileSystem->Server(); - Request request(serv); + Request request(serv, fFileSystem); RequestBuilder& req = request.Builder(); diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Object.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Object.h index 8cb927f118..d0ac9cb83a 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Object.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Object.h @@ -27,10 +27,20 @@ public: static uint32 IncrementSequence(uint32 error); + inline NFS4Object(); + FileInfo fInfo; FileSystem* fFileSystem; }; +inline +NFS4Object::NFS4Object() + : + fFileSystem(NULL) +{ +} + + #endif // NFS4OBJECT_H diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp index 1b09e633a7..8a39021bd8 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp @@ -112,7 +112,7 @@ NFS4Server::ClientId(uint64 prevId, bool forceNew) if ((fUseCount == 0 && fClientIdLastUse + (time_t)LeaseTime() < time(NULL)) || (forceNew && fClientId == prevId)) { - Request request(fServer); + Request request(fServer, NULL); request.Builder().SetClientID(fServer); status_t result = request.Send(); @@ -159,7 +159,7 @@ NFS4Server::FileSystemMigrated() status_t NFS4Server::_GetLeaseTime() { - Request request(fServer); + Request request(fServer, NULL); request.Builder().PutRootFH(); Attribute attr[] = { FATTR4_LEASE_TIME }; request.Builder().GetAttr(attr, sizeof(attr) / sizeof(Attribute)); @@ -246,7 +246,7 @@ NFS4Server::_Renewal() } } - Request request(fServer); + Request request(fServer, NULL); request.Builder().Renew(fClientId); request.Send(); diff --git a/src/add-ons/kernel/file_systems/nfs4/OpenState.cpp b/src/add-ons/kernel/file_systems/nfs4/OpenState.cpp index 7de9b42d04..1655c79170 100644 --- a/src/add-ons/kernel/file_systems/nfs4/OpenState.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/OpenState.cpp @@ -114,7 +114,7 @@ OpenState::_ReleaseLockOwner(LockOwner* owner) { do { RPC::Server* server = fFileSystem->Server(); - Request request(server); + Request request(server, fFileSystem); RequestBuilder& req = request.Builder(); req.ReleaseLockOwner(this, owner); @@ -166,7 +166,7 @@ OpenState::_ReclaimOpen(uint64 newClientID) : OPEN_DELEGATE_NONE; do { RPC::Server* server = fFileSystem->Server(); - Request request(server); + Request request(server, fFileSystem); RequestBuilder& req = request.Builder(); req.PutFH(fInfo.fHandle); @@ -231,7 +231,7 @@ OpenState::_ReclaimLocks(uint64 newClientID) do { RPC::Server* server = fFileSystem->Server(); - Request request(server); + Request request(server, fFileSystem); RequestBuilder& req = request.Builder(); req.PutFH(fInfo.fHandle); @@ -272,7 +272,7 @@ OpenState::Close() uint32 sequence = fFileSystem->OpenOwnerSequenceLock(); do { RPC::Server* serv = fFileSystem->Server(); - Request request(serv); + Request request(serv, fFileSystem); RequestBuilder& req = request.Builder(); req.PutFH(fInfo.fHandle); diff --git a/src/add-ons/kernel/file_systems/nfs4/Request.cpp b/src/add-ons/kernel/file_systems/nfs4/Request.cpp index 5262341889..d68d5b2176 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Request.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Request.cpp @@ -7,9 +7,11 @@ */ -#include "Inode.h" #include "Request.h" +#include "FileSystem.h" +#include "Inode.h" + status_t Request::Send(Cookie* cookie) @@ -36,10 +38,17 @@ Request::_SendUDP(Cookie* cookie) if (cookie != NULL) cookie->RegisterRequest(rpc); + int retryLimit = 0; + bool hard = true; + if (fFileSystem != NULL) { + retryLimit = fFileSystem->GetConfiguration().fRetryLimit; + hard = fFileSystem->GetConfiguration().fHard; + } + result = fServer->WaitCall(rpc); if (result != B_OK) { int attempts = 1; - while (result != B_OK && attempts++ < kRetryLimit) { + while (result != B_OK && (hard || attempts++ < retryLimit)) { result = fServer->ResendCallAsync(fBuilder.Request(), rpc); if (result != B_OK) { if (cookie != NULL) @@ -83,6 +92,15 @@ Request::_SendTCP(Cookie* cookie) status_t result; int attempts = 0; + + int retryLimit = 0; + bool hard = true; + + if (fFileSystem != NULL) { + retryLimit = fFileSystem->GetConfiguration().fRetryLimit; + hard = fFileSystem->GetConfiguration().fHard; + } + do { result = fServer->SendCallAsync(fBuilder.Request(), &rpl, &rpc); if (result == B_NO_MEMORY) @@ -105,7 +123,7 @@ Request::_SendTCP(Cookie* cookie) fServer->Repair(); } - } while (result != B_OK && attempts++ < kRetryLimit); + } while (result != B_OK && (hard || attempts++ < retryLimit)); if (cookie != NULL) cookie->UnregisterRequest(rpc); diff --git a/src/add-ons/kernel/file_systems/nfs4/Request.h b/src/add-ons/kernel/file_systems/nfs4/Request.h index cb8e5e02f4..2c0d014708 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Request.h +++ b/src/add-ons/kernel/file_systems/nfs4/Request.h @@ -15,10 +15,12 @@ class Cookie; +class FileSystem; class Request { public: - inline Request(RPC::Server* serv); + inline Request(RPC::Server* server, + FileSystem* fileSystem); inline RequestBuilder& Builder(); inline ReplyInterpreter& Reply(); @@ -31,18 +33,18 @@ private: status_t _SendTCP(Cookie* cookie); RPC::Server* fServer; + FileSystem* fFileSystem; RequestBuilder fBuilder; ReplyInterpreter fReply; - - static const int kRetryLimit = 5; }; inline -Request::Request(RPC::Server* serv) +Request::Request(RPC::Server* server, FileSystem* fileSystem) : - fServer(serv) + fServer(server), + fFileSystem(fileSystem) { } diff --git a/src/add-ons/kernel/file_systems/nfs4/RootInode.cpp b/src/add-ons/kernel/file_systems/nfs4/RootInode.cpp index 1369d2fe2d..0275f67f01 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RootInode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RootInode.cpp @@ -55,8 +55,8 @@ RootInode::_UpdateInfo(bool force) return B_OK; do { - RPC::Server* serv = fFileSystem->Server(); - Request request(serv); + RPC::Server* server = fFileSystem->Server(); + Request request(server, fFileSystem); RequestBuilder& req = request.Builder(); req.PutFH(fInfo.fHandle); @@ -71,7 +71,7 @@ RootInode::_UpdateInfo(bool force) ReplyInterpreter& reply = request.Reply(); - if (HandleErrors(reply.NFS4Error(), serv)) + if (HandleErrors(reply.NFS4Error(), server)) continue; reply.PutFH(); @@ -137,8 +137,8 @@ bool RootInode::ProbeMigration() { do { - RPC::Server* serv = fFileSystem->Server(); - Request request(serv); + RPC::Server* server = fFileSystem->Server(); + Request request(server, fFileSystem); RequestBuilder& req = request.Builder(); req.PutFH(fInfo.fHandle); @@ -153,7 +153,7 @@ RootInode::ProbeMigration() if (reply.NFS4Error() == NFS4ERR_MOVED) return true; - if (HandleErrors(reply.NFS4Error(), serv)) + if (HandleErrors(reply.NFS4Error(), server)) continue; return false; @@ -166,8 +166,8 @@ status_t RootInode::GetLocations(AttrValue** attrv) { do { - RPC::Server* serv = fFileSystem->Server(); - Request request(serv); + RPC::Server* server = fFileSystem->Server(); + Request request(server, fFileSystem); RequestBuilder& req = request.Builder(); req.PutFH(fInfo.fHandle); @@ -180,7 +180,7 @@ RootInode::GetLocations(AttrValue** attrv) ReplyInterpreter& reply = request.Reply(); - if (HandleErrors(reply.NFS4Error(), serv)) + if (HandleErrors(reply.NFS4Error(), server)) continue; reply.PutFH(); 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 f40cc40f2e..a675138ce9 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -9,6 +9,7 @@ #include +#include #include #include @@ -28,9 +29,6 @@ extern fs_volume_ops gNFSv4VolumeOps; extern fs_vnode_ops gNFSv4VnodeOps; -extern "C" void -dprintf(const char* format, ...); - RPC::ServerManager* gRPCServerManager; @@ -42,30 +40,80 @@ CreateNFS4Server(RPC::Server* serv) } - -// TODO: IPv6 address will cause problems +// Format: ip{4,6}_address:path options +// Available options: +// hard - retry requests until success +// soft - retry requests no more than retrans times (default) +// retrans=X - retry requests X times (default: 5) +// ac - use metadata cache (default) +// noac - do not use metadata cache +// xattr-emu - emulate named attributes +// noxattr-emu - do not emulate named attributes (default) +// port=X - connect to port X (default: 2049) +// proto=X - user transport protocol X (default: tcp) static status_t -ParseArguments(const char* _args, PeerAddress* address, char* _path) +ParseArguments(const char* _args, PeerAddress* address, char** _path, + MountConfiguration* conf) { if (_args == NULL) return B_BAD_VALUE; char* args = strdup(_args); - char* path = strpbrk(args, ":"); - if (path == NULL) { - free(args); + if (args == NULL) + return B_NO_MEMORY; + MemoryDeleter argsDeleter(args); + + char* options = strchr(args, ' '); + if (options != NULL) + *options++ = '\0'; + + char* path = strrchr(args, ':'); + if (path == NULL) return B_MISMATCHED_VALUES; - } *path++ = '\0'; status_t result = PeerAddress::ResolveName(args, address); if (result != B_OK) return result; - _path[255] = '\0'; - strncpy(_path, path, 255); + *_path = strdup(path); + if (*_path == NULL) + return B_NO_MEMORY; + + conf->fHard = false; + conf->fRetryLimit = 5; + conf->fEmulateNamedAttrs = false; + conf->fCacheMetadata = true; + + char* optionsEnd; + if (options != NULL) + optionsEnd = strchr(options, ' '); + while (options != NULL && *options != '\0') { + if (optionsEnd != NULL) + *optionsEnd++ = '\0'; + + if (strcmp(options, "hard") == 0) + conf->fHard = true; + else if (strncmp(options, "retrans=", 8) == 0) { + options += strlen("retrans="); + conf->fRetryLimit = atoi(options); + } else if (strcmp(options, "noac") == 0) + conf->fCacheMetadata = false; + else if (strcmp(options, "xattr-emu") == 0) + conf->fEmulateNamedAttrs = true; + else if (strncmp(options, "port=", 5) == 0) { + options += strlen("port="); + address->SetPort(atoi(options)); + } else if (strncmp(options, "proto=", 6) == 0) { + options += strlen("proto="); + address->SetProtocol(options); + } + + options = optionsEnd; + if (options != NULL) + optionsEnd = strchr(options, ' '); + } - free(args); return B_OK; } @@ -83,10 +131,12 @@ nfs4_mount(fs_volume* volume, const char* device, uint32 flags, locker.Unlock(); PeerAddress address; - char path[256]; - result = ParseArguments(args, &address, path); + MountConfiguration config; + char *path; + result = ParseArguments(args, &address, &path, &config); if (result != B_OK) return result; + MemoryDeleter pathDeleter(path); RPC::Server *server; result = gRPCServerManager->Acquire(&server, address, CreateNFS4Server); @@ -94,7 +144,7 @@ nfs4_mount(fs_volume* volume, const char* device, uint32 flags, return result; FileSystem* fs; - result = FileSystem::Mount(&fs, server, path, volume->id); + result = FileSystem::Mount(&fs, server, path, volume->id, config); if (result != B_OK) { gRPCServerManager->Release(server); return result; @@ -824,8 +874,6 @@ nfs4_release_lock(fs_volume* volume, fs_vnode* vnode, void* _cookie, status_t nfs4_init() { - dprintf("NFS4 Init\n"); - gRPCServerManager = new(std::nothrow) RPC::ServerManager; if (gRPCServerManager == NULL) return B_NO_MEMORY; @@ -856,8 +904,6 @@ nfs4_init() status_t nfs4_uninit() { - dprintf("NFS4 Uninit\n"); - delete gRPCCallbackServer; delete gIdMapper; delete gWorkQueue; From e8c12d9410d16c9a504198755b85c385e7ab667a Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Thu, 16 Aug 2012 21:11:56 +0200 Subject: [PATCH 201/252] nfs4: Fix file handle recovery --- .../file_systems/nfs4/DirectoryCache.cpp | 38 +++++++++----- .../kernel/file_systems/nfs4/FileInfo.cpp | 2 +- .../kernel/file_systems/nfs4/FileSystem.cpp | 34 +++++++----- .../kernel/file_systems/nfs4/Inode.cpp | 52 +++++++++++++------ src/add-ons/kernel/file_systems/nfs4/Inode.h | 11 +--- .../kernel/file_systems/nfs4/InodeIdMap.h | 7 +-- .../kernel/file_systems/nfs4/RootInode.cpp | 12 ++++- .../kernel/file_systems/nfs4/RootInode.h | 13 +++++ 8 files changed, 111 insertions(+), 58 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.cpp b/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.cpp index 52be9fddff..370a3378a5 100644 --- a/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.cpp @@ -184,7 +184,7 @@ status_t DirectoryCache::Revalidate() { uint64 change; - if (fInode->GetChangeInfo(&change, true) != B_OK) { + if (fInode->GetChangeInfo(&change, fAttrDir) != B_OK) { Trash(); return B_ERROR; } @@ -263,24 +263,34 @@ DirectoryCache::NotifyChanges(DirectoryCacheSnapshot* oldSnapshot, notify_entry_created(fInode->GetFileSystem()->DevId(), fInode->ID(), newCurrent->fName, newCurrent->fNode); - FileInfo fi; - fi.fFileId = newCurrent->fNode; - fi.fParent = fInode->fInfo.fHandle; - fi.fName = strdup(newCurrent->fName); - if (fi.fName != NULL) { - size_t pathLength = strlen(newCurrent->fName) + 2 + - strlen(fInode->fInfo.fPath); - char* path = reinterpret_cast(malloc(pathLength)); - if (path != NULL) { + do { + FileInfo fi; + fi.fFileId = newCurrent->fNode; + fi.fParent = fInode->fInfo.fHandle; + fi.fName = strdup(newCurrent->fName); + if (fi.fName == NULL) + break; + + if (fInode->fInfo.fPath != NULL) { + size_t pathLength = strlen(newCurrent->fName) + 2 + + strlen(fInode->fInfo.fPath); + char* path = reinterpret_cast(pathLength); + if (path == NULL) + break; + strcpy(path, fInode->fInfo.fPath); strcat(path, "/"); strcat(path, newCurrent->fName); fi.fPath = path; - - fInode->GetFileSystem()->InoIdMap()->AddEntry(fi, - Inode::FileIdToInoT(newCurrent->fNode)); + } else { + fi.fPath = strdup(newCurrent->fName); + if (fi.fPath == NULL) + break; } - } + + fInode->GetFileSystem()->InoIdMap()->AddEntry(fi, + Inode::FileIdToInoT(newCurrent->fNode), true); + } while (false); } } else oldSnapshot->fEntries.Remove(prev, oldCurrent); diff --git a/src/add-ons/kernel/file_systems/nfs4/FileInfo.cpp b/src/add-ons/kernel/file_systems/nfs4/FileInfo.cpp index e81242e526..9ff0e49211 100644 --- a/src/add-ons/kernel/file_systems/nfs4/FileInfo.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/FileInfo.cpp @@ -56,7 +56,7 @@ FileInfo::UpdateFileHandles(FileSystem* fs) uint32 lookupCount = 0; status_t result; - +dprintf("%s %s\n", fs->Path(), fPath); result = ParsePath(req, lookupCount, fs->Path()); if (result != B_OK) return result; diff --git a/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp b/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp index 4c8963aa9e..ec5d992987 100644 --- a/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp @@ -58,10 +58,11 @@ FileSystem::~FileSystem() static const char* -sGetPath(const char* root, const char* path) +GetPath(const char* root, const char* path) { int slash = 0; - for (int i = 0; path[i] != '\0'; i++) { + int i; + for (i = 0; path[i] != '\0'; i++) { if (path[i] != root[i] || root[i] == '\0') break; @@ -69,6 +70,9 @@ sGetPath(const char* root, const char* path) slash = i; } + if (path[i] == '\0') + return NULL; + return path + slash; } @@ -149,12 +153,6 @@ FileSystem::Mount(FileSystem** pfs, RPC::Server* serv, const char* fsPath, const char* name; if (fsPath != NULL && fsPath[0] == '/') fsPath++; - name = strrchr(fsPath, '/'); - if (name != NULL) { - name++; - fi.fName = strdup(name); - } else - fi.fName = strdup(fsPath); fs->fServer = serv; fs->fDevId = id; @@ -162,18 +160,30 @@ FileSystem::Mount(FileSystem** pfs, RPC::Server* serv, const char* fsPath, fi.fHandle = fh; fi.fParent = fh; - fi.fPath = strdup(sGetPath(fs->fPath, fsPath)); + fi.fPath = strdup(GetPath(fs->fPath, fsPath)); + + if (fi.fPath != NULL) { + name = strrchr(fi.fPath, '/'); + if (name != NULL) { + name++; + fi.fName = strdup(name); + } + } delete[] values; - if (fi.fName == NULL || fi.fPath == NULL) - return B_NO_MEMORY; - Inode* inode; result = Inode::CreateInode(fs, fi, &inode); if (result != B_OK) return result; + name = strrchr(fsPath, '/'); + if (name != NULL) { + name++; + reinterpret_cast(inode)->SetName(name); + } else + reinterpret_cast(inode)->SetName(fsPath); + fs->fRoot = reinterpret_cast(inode); fs->NFSServer()->AddFileSystem(fs); diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index c8cfd2c808..a98ca4c67b 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -230,16 +230,21 @@ Inode::Link(Inode* dir, const char* name) if (fi.fName == NULL) return B_NO_MEMORY; - char* path = reinterpret_cast(malloc(strlen(name) + 2 + - strlen(fInfo.fPath))); - if (path == NULL) - return B_NO_MEMORY; + if (fInfo.fPath != NULL) { + char* path = reinterpret_cast(malloc(strlen(name) + 2 + + strlen(fInfo.fPath))); + if (path == NULL) + return B_NO_MEMORY; - strcpy(path, dir->fInfo.fPath); - strcat(path, "/"); - strcat(path, name); - free(const_cast(fi.fPath)); - fi.fPath = path; + strcpy(path, fInfo.fPath); + strcat(path, "/"); + strcat(path, name); + fi.fPath = path; + } else { + fi.fPath = strdup(name); + if (fi.fPath == NULL) + return B_NO_MEMORY; + } fFileSystem->InoIdMap()->AddEntry(fi, fInfo.fFileId); @@ -803,20 +808,33 @@ Inode::ChildAdded(const char* name, uint64 fileID, if (fi.fName == NULL) return B_NO_MEMORY; - char* path = reinterpret_cast(malloc(strlen(name) + 2 + - strlen(fInfo.fPath))); - if (path == NULL) - return B_NO_MEMORY; + if (fInfo.fPath != NULL) { + char* path = reinterpret_cast(malloc(strlen(name) + 2 + + strlen(fInfo.fPath))); + if (path == NULL) + return B_NO_MEMORY; - strcpy(path, fInfo.fPath); - strcat(path, "/"); - strcat(path, name); - fi.fPath = path; + strcpy(path, fInfo.fPath); + strcat(path, "/"); + strcat(path, name); + fi.fPath = path; + } else { + fi.fPath = strdup(name); + if (fi.fPath == NULL) + return B_NO_MEMORY; + } return fFileSystem->InoIdMap()->AddEntry(fi, FileIdToInoT(fileID)); } +const char* +Inode::Name() const +{ + return fInfo.fName; +} + + void Inode::SetDelegation(Delegation* delegation) { diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h b/src/add-ons/kernel/file_systems/nfs4/Inode.h index d4d16acdae..7497fa5fd2 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -20,11 +20,11 @@ class Inode : public NFS4Inode { public: static status_t CreateInode(FileSystem* fs, const FileInfo& fi, Inode** inode); - ~Inode(); + virtual ~Inode(); inline ino_t ID() const; inline mode_t Type() const; - inline const char* Name() const; + virtual const char* Name() const; inline FileSystem* GetFileSystem() const; inline void SetOpenState(OpenState* state); @@ -181,13 +181,6 @@ Inode::Type() const } -inline const char* -Inode::Name() const -{ - return fInfo.fName; -} - - inline FileSystem* Inode::GetFileSystem() const { diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeIdMap.h b/src/add-ons/kernel/file_systems/nfs4/InodeIdMap.h index 2a29e07942..ae85c32594 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeIdMap.h +++ b/src/add-ons/kernel/file_systems/nfs4/InodeIdMap.h @@ -23,7 +23,7 @@ public: inline ~InodeIdMap(); inline status_t AddEntry(const FileInfo& fi, - ino_t id); + ino_t id, bool weak = false); inline status_t RemoveEntry(ino_t id); inline status_t GetFileInfo(FileInfo* fi, ino_t id); @@ -49,10 +49,11 @@ InodeIdMap::~InodeIdMap() inline status_t -InodeIdMap::AddEntry(const FileInfo& fi, ino_t id) +InodeIdMap::AddEntry(const FileInfo& fi, ino_t id, bool weak) { MutexLocker _(fLock); - fMap.Remove(id); + //if (weak) + fMap.Remove(id); return fMap.Insert(id, fi); } diff --git a/src/add-ons/kernel/file_systems/nfs4/RootInode.cpp b/src/add-ons/kernel/file_systems/nfs4/RootInode.cpp index 0275f67f01..4ca51e2021 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RootInode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RootInode.cpp @@ -18,6 +18,7 @@ RootInode::RootInode() : fInfoCacheExpire(0), + fName(NULL), fIOSize(0) { mutex_init(&fInfoCacheLock, NULL); @@ -26,6 +27,7 @@ RootInode::RootInode() RootInode::~RootInode() { + free(const_cast(fName)); mutex_destroy(&fInfoCacheLock); } @@ -125,7 +127,7 @@ RootInode::_UpdateInfo(bool force) } while (true); fInfoCache.flags = 0; - strncpy(fInfoCache.volume_name, fInfo.fName, B_FILE_NAME_LENGTH); + strncpy(fInfoCache.volume_name, fName, B_FILE_NAME_LENGTH); fInfoCacheExpire = time(NULL) + MetadataCache::kExpirationTime; @@ -161,7 +163,6 @@ RootInode::ProbeMigration() } - status_t RootInode::GetLocations(AttrValue** attrv) { @@ -198,3 +199,10 @@ RootInode::GetLocations(AttrValue** attrv) return B_OK; } + +const char* +RootInode::Name() const +{ + return fName; +} + diff --git a/src/add-ons/kernel/file_systems/nfs4/RootInode.h b/src/add-ons/kernel/file_systems/nfs4/RootInode.h index 864d49ddba..4810b7829d 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RootInode.h +++ b/src/add-ons/kernel/file_systems/nfs4/RootInode.h @@ -19,6 +19,9 @@ public: RootInode(); ~RootInode(); + virtual const char* Name() const; + inline void SetName(const char* name); + status_t ReadInfo(struct fs_info* info); inline void MakeInfoInvalid(); @@ -32,6 +35,8 @@ private: mutex fInfoCacheLock; time_t fInfoCacheExpire; + const char* fName; + uint32 fIOSize; status_t _UpdateInfo(bool force = false); @@ -55,5 +60,13 @@ RootInode::IOSize() } +inline void +RootInode::SetName(const char* name) +{ + free(const_cast(fName)); + fName = strdup(name); +} + + #endif // ROOTINODE_H From da950cb2ef76ecc309a833bcf9cc748b16f78bc1 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Fri, 17 Aug 2012 01:14:30 +0200 Subject: [PATCH 202/252] nfs4: Fix several problems with emulated attributes --- .../kernel/file_systems/nfs4/Inode.cpp | 17 +++++++++++++++++ src/add-ons/kernel/file_systems/nfs4/Inode.h | 2 ++ .../kernel/file_systems/nfs4/InodeDir.cpp | 4 ++-- .../kernel/file_systems/nfs4/InodeRegular.cpp | 19 +++++++++++-------- .../kernel/file_systems/nfs4/RootInode.cpp | 8 +++++++- 5 files changed, 39 insertions(+), 11 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index a98ca4c67b..4b179c5ef8 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -12,6 +12,7 @@ #include #include +#include #include #include @@ -267,10 +268,16 @@ Inode::Link(Inode* dir, const char* name) status_t Inode::Remove(const char* name, FileType type) { + MemoryDeleter nameDeleter; if (type == NF4NAMEDATTR) { status_t result = LoadAttrDirHandle(); if (result != B_OK) return result; + + name = AttrToFileName(name); + if (name == NULL) + return B_NO_MEMORY; + nameDeleter.SetTo(const_cast(name)); } ChangeInfo changeInfo; @@ -311,6 +318,8 @@ Inode::Rename(Inode* from, Inode* to, const char* fromName, const char* toName, if (from->fFileSystem != to->fFileSystem) return B_DONT_DO_THAT; + MemoryDeleter fromNameDeleter; + MemoryDeleter toNameDeleter; if (attribute) { status_t result = from->LoadAttrDirHandle(); if (result != B_OK) @@ -319,6 +328,14 @@ Inode::Rename(Inode* from, Inode* to, const char* fromName, const char* toName, result = to->LoadAttrDirHandle(); if (result != B_OK) return result; + + fromName = from->AttrToFileName(fromName); + toName = to->AttrToFileName(toName); + + fromNameDeleter.SetTo(const_cast(fromName)); + toNameDeleter.SetTo(const_cast(toName)); + if (fromName == NULL || toName == NULL) + return B_NO_MEMORY; } ChangeInfo fromChange, toChange; diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h b/src/add-ons/kernel/file_systems/nfs4/Inode.h index 7497fa5fd2..3815e9741e 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -132,6 +132,8 @@ protected: status_t GetStat(struct stat* st, OpenAttrCookie* attr = NULL); + char* AttrToFileName(const char* path); + static inline status_t CheckLockType(short ltype, uint32 mode); private: diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp b/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp index 65f735aa79..5633fba537 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp @@ -85,11 +85,11 @@ Inode::LoadAttrDirHandle() return B_UNSUPPORTED; char* attrDir - = reinterpret_cast(malloc(strlen(fInfo.fName) + 32)); + = reinterpret_cast(malloc(strlen(Name()) + 32)); if (attrDir == NULL) return B_NO_MEMORY; strcpy(attrDir, "."); - strcat(attrDir, fInfo.fName); + strcat(attrDir, Name()); strcat(attrDir, "-haiku-attrs"); result = NFS4Inode::LookUp(attrDir, NULL, NULL, &handle, true); diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp index 4d1b943e4e..b677477963 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp @@ -40,12 +40,15 @@ Inode::CreateState(const char* name, int mode, int perms, OpenState* state, fi.fParent = fInfo.fHandle; fi.fName = strdup(name); - char* path = reinterpret_cast(malloc(strlen(name) + 2 + - strlen(fInfo.fPath))); - strcpy(path, fInfo.fPath); - strcat(path, "/"); - strcat(path, name); - fi.fPath = path; + if (fInfo.fPath != NULL) { + char* path = reinterpret_cast(malloc(strlen(name) + 2 + + strlen(fInfo.fPath))); + strcpy(path, fInfo.fPath); + strcat(path, "/"); + strcat(path, name); + fi.fPath = path; + } else + fi.fPath = strdup(name); fFileSystem->InoIdMap()->AddEntry(fi, FileIdToInoT(fileID)); @@ -193,8 +196,8 @@ Inode::Close(OpenFileCookie* cookie) } -static char* -AttrToFileName(const char* path) +char* +Inode::AttrToFileName(const char* path) { char* name = strdup(path); if (name == NULL) diff --git a/src/add-ons/kernel/file_systems/nfs4/RootInode.cpp b/src/add-ons/kernel/file_systems/nfs4/RootInode.cpp index 4ca51e2021..65fbd73247 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RootInode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RootInode.cpp @@ -126,7 +126,13 @@ RootInode::_UpdateInfo(bool force) break; } while (true); - fInfoCache.flags = 0; + fInfoCache.flags = B_FS_IS_PERSISTENT | B_FS_IS_SHARED + | B_FS_SUPPORTS_NODE_MONITORING; + + if (fFileSystem->NamedAttrs() + || fFileSystem->GetConfiguration().fEmulateNamedAttrs) + fInfoCache.flags |= B_FS_HAS_MIME | B_FS_HAS_ATTR; + strncpy(fInfoCache.volume_name, fName, B_FILE_NAME_LENGTH); fInfoCacheExpire = time(NULL) + MetadataCache::kExpirationTime; From 8568341ae61b9ecdd5f96b6167c5eb5589a20ed1 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Fri, 17 Aug 2012 01:28:48 +0200 Subject: [PATCH 203/252] nfs4: Fix bugs when metadata cache is disabled --- src/add-ons/kernel/file_systems/nfs4/Inode.cpp | 7 ++++++- src/add-ons/kernel/file_systems/nfs4/MetadataCache.cpp | 7 ++----- src/add-ons/kernel/file_systems/nfs4/MetadataCache.h | 6 ++++-- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index 4b179c5ef8..29f9cb7bb2 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -430,8 +430,9 @@ Inode::Access(int mode) int acc = 0; uint32 allowed; + bool cache = fFileSystem->GetConfiguration().fCacheMetadata; status_t result = fMetaCache.GetAccess(geteuid(), &allowed); - if (result != B_OK) { + if (result != B_OK || !cache) { result = NFS4Inode::Access(&allowed); if (result != B_OK) return result; @@ -463,6 +464,10 @@ Inode::Stat(struct stat* st, OpenAttrCookie* attr) if (attr != NULL) return GetStat(st, attr); + bool cache = fFileSystem->GetConfiguration().fCacheMetadata; + if (!cache) + return GetStat(st, NULL); + status_t result = fMetaCache.GetStat(st); if (result != B_OK) { struct stat temp; diff --git a/src/add-ons/kernel/file_systems/nfs4/MetadataCache.cpp b/src/add-ons/kernel/file_systems/nfs4/MetadataCache.cpp index bc345a9401..38795b4402 100644 --- a/src/add-ons/kernel/file_systems/nfs4/MetadataCache.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/MetadataCache.cpp @@ -35,8 +35,7 @@ status_t MetadataCache::GetStat(struct stat* st) { MutexLocker _(fLock); - bool cache = fInode->GetFileSystem()->GetConfiguration().fCacheMetadata; - if (fForceValid || (cache && fExpire > time(NULL))) { + if (fForceValid || fExpire > time(NULL)) { // Do not touch other members of struct stat st->st_size = fStatCache.st_size; st->st_mode = fStatCache.st_mode; @@ -112,9 +111,7 @@ MetadataCache::SetAccess(uid_t uid, uint32 allowed) entry.fExpire = time(NULL) + kExpirationTime; entry.fForceValid = fForceValid; - bool cache = fInode->GetFileSystem()->GetConfiguration().fCacheMetadata; - if (fForceValid || cache) - fAccessCache.Insert(uid, entry); + fAccessCache.Insert(uid, entry); } diff --git a/src/add-ons/kernel/file_systems/nfs4/MetadataCache.h b/src/add-ons/kernel/file_systems/nfs4/MetadataCache.h index 07a13a3c58..82e44c6496 100644 --- a/src/add-ons/kernel/file_systems/nfs4/MetadataCache.h +++ b/src/add-ons/kernel/file_systems/nfs4/MetadataCache.h @@ -69,7 +69,8 @@ inline void MetadataCache::InvalidateStat() { MutexLocker _(fLock); - fExpire = 0; + if (!fForceValid) + fExpire = 0; } @@ -77,7 +78,8 @@ inline void MetadataCache::InvalidateAccess() { MutexLocker _(fLock); - fAccessCache.MakeEmpty(); + if (!fForceValid) + fAccessCache.MakeEmpty(); } From 7c6cdb836049521a65ae47018e15020b1701dc5c Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Fri, 17 Aug 2012 02:51:20 +0200 Subject: [PATCH 204/252] nfs4: Fix node removal --- src/add-ons/kernel/file_systems/nfs4/Inode.cpp | 4 +++- src/add-ons/kernel/file_systems/nfs4/Inode.h | 3 ++- src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h | 7 +++++++ .../kernel/file_systems/nfs4/NFS4Inode.cpp | 6 ++---- .../kernel/file_systems/nfs4/NFS4Object.cpp | 3 ++- .../file_systems/nfs4/ReplyInterpreter.cpp | 8 +++++++- .../file_systems/nfs4/kernel_interface.cpp | 16 +++++++++++++--- 7 files changed, 36 insertions(+), 11 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index 29f9cb7bb2..2ff488e8de 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -266,7 +266,7 @@ Inode::Link(Inode* dir, const char* name) status_t -Inode::Remove(const char* name, FileType type) +Inode::Remove(const char* name, FileType type, ino_t* id) { MemoryDeleter nameDeleter; if (type == NF4NAMEDATTR) { @@ -298,6 +298,8 @@ Inode::Remove(const char* name, FileType type) } fFileSystem->Root()->MakeInfoInvalid(); + if (id != NULL) + *id = FileIdToInoT(fileID); if (type == NF4NAMEDATTR) { notify_attribute_changed(fFileSystem->DevId(), ID(), name, diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h b/src/add-ons/kernel/file_systems/nfs4/Inode.h index 3815e9741e..6c9e1fc9de 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -57,7 +57,8 @@ public: int mode); status_t Link(Inode* dir, const char* name); - status_t Remove(const char* name, FileType type); + status_t Remove(const char* name, FileType type, + ino_t* id); static status_t Rename(Inode* from, Inode* to, const char* fromName, const char* toName, bool attribute = false); diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h index 1a617ff67f..236d37742f 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h @@ -303,6 +303,13 @@ enum Errors { NFS4ERR_ISDIR = 21, NFS4ERR_INVAL = 22, NFS4ERR_FBIG = 27, + NFS4ERR_NOSPC = 28, + NFS4ERR_ROFS = 30, + NFS4ERR_MLINK = 31, + NFS4ERR_NAMETOOLONG = 63, + NFS4ERR_NOTEMPTY = 66, + NFS4ERR_DQUOT = 69, + NFS4ERR_STALE = 70, NFS4ERR_BADHANDLE = 10001, NFS4ERR_BAD_COOKIE = 10003, NFS4ERR_NOTSUPP = 10004, diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp index 43ae3fe060..3ae8de5beb 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp @@ -824,13 +824,12 @@ NFS4Inode::RemoveObject(const char* name, FileType type, ChangeInfo* changeInfo, else req.Nverify(&attr, 1); - req.PutFH(fInfo.fHandle); - if (type != NF4NAMEDATTR) { Attribute idAttr[] = { FATTR4_FILEID }; req.GetAttr(idAttr, sizeof(idAttr) / sizeof(Attribute)); } + req.PutFH(fInfo.fHandle); req.Remove(name); status_t result = request.Send(); @@ -859,8 +858,6 @@ NFS4Inode::RemoveObject(const char* name, FileType type, ChangeInfo* changeInfo, if (result != B_OK) return result; - reply.PutFH(); - if (type != NF4NAMEDATTR) { AttrValue* values; uint32 count; @@ -875,6 +872,7 @@ NFS4Inode::RemoveObject(const char* name, FileType type, ChangeInfo* changeInfo, delete[] values; } + reply.PutFH(); return reply.Remove(&changeInfo->fBefore, &changeInfo->fAfter, changeInfo->fAtomic); } while (true); diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp index e24abcecd0..918c44f473 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp @@ -110,10 +110,11 @@ NFS4Object::HandleErrors(uint32 nfs4Error, RPC::Server* serv, } return false; - // FileHandle has expired or is invalid + // File Handle has expired, is invalid or the node has been deleted case NFS4ERR_NOFILEHANDLE: case NFS4ERR_BADHANDLE: case NFS4ERR_FHEXPIRED: + case NFS4ERR_STALE: if (fInfo.UpdateFileHandles(fFileSystem) == B_OK) return true; return false; diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp index bf4f4dd2ac..4ed2023277 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp @@ -829,13 +829,19 @@ ReplyInterpreter::_NFS4ErrorToHaiku(uint32 x) case NFS4ERR_INVAL: return B_BAD_VALUE; case NFS4ERR_FBIG: return B_FILE_TOO_LARGE; case NFS4ERR_NOTSUPP: return B_UNSUPPORTED; + case NFS4ERR_ROFS: return B_READ_ONLY_DEVICE; + case NFS4ERR_NAMETOOLONG: return B_NAME_TOO_LONG; + case NFS4ERR_NOTEMPTY: return B_DIRECTORY_NOT_EMPTY; // ... case NFS4ERR_DELAY: case NFS4ERR_DENIED: case NFS4ERR_LOCKED: case NFS4ERR_GRACE: return B_WOULD_BLOCK; - case NFS4ERR_FHEXPIRED: return B_ENTRY_NOT_FOUND; + + case NFS4ERR_STALE: + case NFS4ERR_FHEXPIRED: + return B_FILE_NOT_FOUND; // ... default: return B_ERROR; } 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 a675138ce9..c2e4b6ae17 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -413,7 +413,13 @@ static status_t nfs4_unlink(fs_volume* volume, fs_vnode* dir, const char* name) { Inode* inode = reinterpret_cast(dir->private_node); - return inode->Remove(name, NF4REG); + + ino_t id; + status_t result = inode->Remove(name, NF4REG, &id); + if (result != B_OK) + return result; + + return remove_vnode(volume, id); } @@ -607,7 +613,11 @@ static status_t nfs4_remove_dir(fs_volume* volume, fs_vnode* parent, const char* name) { Inode* inode = reinterpret_cast(parent->private_node); - return inode->Remove(name, NF4DIR); + ino_t id; + status_t result = inode->Remove(name, NF4DIR, &id); + if (result != B_OK) + return result; + return remove_vnode(volume, id); } @@ -826,7 +836,7 @@ static status_t nfs4_remove_attr(fs_volume* volume, fs_vnode* vnode, const char* name) { Inode* inode = reinterpret_cast(vnode->private_node); - return inode->Remove(name, NF4NAMEDATTR); + return inode->Remove(name, NF4NAMEDATTR, NULL); } From dee0fd8348ec064654517af747c9554c993eed4f Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Fri, 17 Aug 2012 03:13:02 +0200 Subject: [PATCH 205/252] nfs4: Update FileInfo at rename --- .../file_systems/nfs4/DirectoryCache.cpp | 22 ++------ .../kernel/file_systems/nfs4/FileInfo.cpp | 34 +++++++++++- .../kernel/file_systems/nfs4/FileInfo.h | 4 +- .../kernel/file_systems/nfs4/Inode.cpp | 54 +++++-------------- src/add-ons/kernel/file_systems/nfs4/Inode.h | 4 +- .../kernel/file_systems/nfs4/InodeRegular.cpp | 12 +---- .../kernel/file_systems/nfs4/NFS4Inode.cpp | 2 +- .../kernel/file_systems/nfs4/NFS4Inode.h | 2 +- .../file_systems/nfs4/kernel_interface.cpp | 16 +++++- 9 files changed, 71 insertions(+), 79 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.cpp b/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.cpp index 370a3378a5..979838655c 100644 --- a/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.cpp @@ -267,27 +267,11 @@ DirectoryCache::NotifyChanges(DirectoryCacheSnapshot* oldSnapshot, FileInfo fi; fi.fFileId = newCurrent->fNode; fi.fParent = fInode->fInfo.fHandle; - fi.fName = strdup(newCurrent->fName); - if (fi.fName == NULL) + status_t result = fi.CreateName(fInode->fInfo.fPath, + newCurrent->fName); + if (result != B_OK) break; - if (fInode->fInfo.fPath != NULL) { - size_t pathLength = strlen(newCurrent->fName) + 2 + - strlen(fInode->fInfo.fPath); - char* path = reinterpret_cast(pathLength); - if (path == NULL) - break; - - strcpy(path, fInode->fInfo.fPath); - strcat(path, "/"); - strcat(path, newCurrent->fName); - fi.fPath = path; - } else { - fi.fPath = strdup(newCurrent->fName); - if (fi.fPath == NULL) - break; - } - fInode->GetFileSystem()->InoIdMap()->AddEntry(fi, Inode::FileIdToInoT(newCurrent->fNode), true); } while (false); diff --git a/src/add-ons/kernel/file_systems/nfs4/FileInfo.cpp b/src/add-ons/kernel/file_systems/nfs4/FileInfo.cpp index 9ff0e49211..b33eaa42c4 100644 --- a/src/add-ons/kernel/file_systems/nfs4/FileInfo.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/FileInfo.cpp @@ -46,6 +46,38 @@ FileInfo::ParsePath(RequestBuilder& req, uint32& count, const char* _path) } +status_t +FileInfo::CreateName(const char* dirPath, const char* name) +{ + free(const_cast(fName)); + fName = strdup(name); + if (fName == NULL) + return B_NO_MEMORY; + + if (dirPath != NULL) { + char* path = reinterpret_cast(malloc(strlen(name) + 2 + + strlen(dirPath))); + if (path == NULL) + return B_NO_MEMORY; + + strcpy(path, dirPath); + strcat(path, "/"); + strcat(path, name); + + free(const_cast(fPath)); + fPath = path; + } else { + free(const_cast(fPath)); + fPath = strdup(name); + } + + if (fPath == NULL) + return B_NO_MEMORY; + + return B_OK; +} + + status_t FileInfo::UpdateFileHandles(FileSystem* fs) { @@ -56,7 +88,7 @@ FileInfo::UpdateFileHandles(FileSystem* fs) uint32 lookupCount = 0; status_t result; -dprintf("%s %s\n", fs->Path(), fPath); + result = ParsePath(req, lookupCount, fs->Path()); if (result != B_OK) return result; diff --git a/src/add-ons/kernel/file_systems/nfs4/FileInfo.h b/src/add-ons/kernel/file_systems/nfs4/FileInfo.h index ecacc0cace..4182dcc331 100644 --- a/src/add-ons/kernel/file_systems/nfs4/FileInfo.h +++ b/src/add-ons/kernel/file_systems/nfs4/FileInfo.h @@ -55,8 +55,10 @@ struct FileInfo { status_t UpdateFileHandles(FileSystem* fs); - static status_t ParsePath(RequestBuilder& req, uint32& count, + static status_t ParsePath(RequestBuilder& req, uint32& count, const char* _path); + + status_t CreateName(const char* dirPath, const char* name); }; struct FileSystemId { diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index 2ff488e8de..d52409deb3 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -226,26 +226,9 @@ Inode::Link(Inode* dir, const char* name) FileInfo fi = fInfo; fi.fParent = dir->fInfo.fHandle; - free(const_cast(fi.fName)); - fi.fName = strdup(name); - if (fi.fName == NULL) - return B_NO_MEMORY; - - if (fInfo.fPath != NULL) { - char* path = reinterpret_cast(malloc(strlen(name) + 2 + - strlen(fInfo.fPath))); - if (path == NULL) - return B_NO_MEMORY; - - strcpy(path, fInfo.fPath); - strcat(path, "/"); - strcat(path, name); - fi.fPath = path; - } else { - fi.fPath = strdup(name); - if (fi.fPath == NULL) - return B_NO_MEMORY; - } + result = fi.CreateName(fInfo.fPath, name); + if (result != B_OK) + return result; fFileSystem->InoIdMap()->AddEntry(fi, fInfo.fFileId); @@ -315,7 +298,7 @@ Inode::Remove(const char* name, FileType type, ino_t* id) status_t Inode::Rename(Inode* from, Inode* to, const char* fromName, const char* toName, - bool attribute) + bool attribute, ino_t* id) { if (from->fFileSystem != to->fFileSystem) return B_DONT_DO_THAT; @@ -342,8 +325,8 @@ Inode::Rename(Inode* from, Inode* to, const char* fromName, const char* toName, ChangeInfo fromChange, toChange; uint64 fileID; - status_t result = NFS4Inode::Rename(from, to, fromName, toName, &fromChange, - &toChange, &fileID, attribute); + status_t result = NFS4Inode::RenameNode(from, to, fromName, toName, + &fromChange, &toChange, &fileID, attribute); if (result != B_OK) return result; @@ -360,6 +343,9 @@ Inode::Rename(Inode* from, Inode* to, const char* fromName, const char* toName, cache->Unlock(); } + if (id != NULL) + *id = FileIdToInoT(fileID); + cache = attribute ? to->fAttrCache : to->fCache; if (cache->Lock() == B_OK) { if (toChange.fAtomic @@ -828,25 +814,9 @@ Inode::ChildAdded(const char* name, uint64 fileID, fi.fFileId = fileID; fi.fHandle = fileHandle; fi.fParent = fInfo.fHandle; - fi.fName = strdup(name); - if (fi.fName == NULL) - return B_NO_MEMORY; - - if (fInfo.fPath != NULL) { - char* path = reinterpret_cast(malloc(strlen(name) + 2 + - strlen(fInfo.fPath))); - if (path == NULL) - return B_NO_MEMORY; - - strcpy(path, fInfo.fPath); - strcat(path, "/"); - strcat(path, name); - fi.fPath = path; - } else { - fi.fPath = strdup(name); - if (fi.fPath == NULL) - return B_NO_MEMORY; - } + status_t result = fi.CreateName(fInfo.fPath, name); + if (result != B_OK) + return result; return fFileSystem->InoIdMap()->AddEntry(fi, FileIdToInoT(fileID)); } diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h b/src/add-ons/kernel/file_systems/nfs4/Inode.h index 6c9e1fc9de..6a89c949e7 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -58,10 +58,10 @@ public: status_t Link(Inode* dir, const char* name); status_t Remove(const char* name, FileType type, - ino_t* id); + ino_t* id = NULL); static status_t Rename(Inode* from, Inode* to, const char* fromName, const char* toName, - bool attribute = false); + bool attribute = false, ino_t* id = NULL); status_t Stat(struct stat* st, OpenAttrCookie* attr = NULL); diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp index b677477963..756d49e44d 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp @@ -38,17 +38,7 @@ Inode::CreateState(const char* name, int mode, int perms, OpenState* state, fi.fFileId = fileID; fi.fHandle = handle; fi.fParent = fInfo.fHandle; - fi.fName = strdup(name); - - if (fInfo.fPath != NULL) { - char* path = reinterpret_cast(malloc(strlen(name) + 2 + - strlen(fInfo.fPath))); - strcpy(path, fInfo.fPath); - strcat(path, "/"); - strcat(path, name); - fi.fPath = path; - } else - fi.fPath = strdup(name); + fi.CreateName(fInfo.fPath, name); fFileSystem->InoIdMap()->AddEntry(fi, FileIdToInoT(fileID)); diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp index 3ae8de5beb..fa50569be9 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp @@ -329,7 +329,7 @@ NFS4Inode::WriteStat(OpenState* state, AttrValue* attrs, uint32 attrCount) status_t -NFS4Inode::Rename(Inode* from, Inode* to, const char* fromName, +NFS4Inode::RenameNode(Inode* from, Inode* to, const char* fromName, const char* toName, ChangeInfo* fromChange, ChangeInfo* toChange, uint64* fileID, bool attribute) { diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h index cd3c461c77..4aff6886c9 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.h @@ -36,7 +36,7 @@ protected: status_t Link(Inode* dir, const char* name, ChangeInfo* changeInfo); - static status_t Rename(Inode* from, Inode* to, const char* fromName, + static status_t RenameNode(Inode* from, Inode* to, const char* fromName, const char* toName, ChangeInfo* fromChange, ChangeInfo* toChange, uint64* fileID, bool attribute = false); 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 c2e4b6ae17..9958fa02e6 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -429,7 +429,21 @@ nfs4_rename(fs_volume* volume, fs_vnode* fromDir, const char* fromName, { Inode* fromInode = reinterpret_cast(fromDir->private_node); Inode* toInode = reinterpret_cast(toDir->private_node); - return Inode::Rename(fromInode, toInode, fromName, toName); + + ino_t id; + status_t result = Inode::Rename(fromInode, toInode, fromName, toName, false, + &id); + if (result != B_OK) + return result; + + Inode* child; + result = get_vnode(volume, id, reinterpret_cast(&child)); + if (result == B_OK) { + child->fInfo.fParent = toInode->fInfo.fHandle; + child->fInfo.CreateName(toInode->fInfo.fPath, toName); + } + + return B_OK; } From e422d059c8b56324f663ad5d2f611cfa109643e8 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Fri, 17 Aug 2012 03:32:57 +0200 Subject: [PATCH 206/252] nfs4: Properly handle NFS4ERR_DELAY during node rename --- src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp index fa50569be9..dd590085fa 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp @@ -374,6 +374,12 @@ NFS4Inode::RenameNode(Inode* from, Inode* to, const char* fromName, continue; } + // need to wait + if (reply.NFS4Error() == NFS4ERR_DELAY) { + snooze_etc(sSecToBigTime(5), B_SYSTEM_TIMEBASE, B_RELATIVE_TIMEOUT); + continue; + } + reply.PutFH(); reply.SaveFH(); reply.PutFH(); From cae470f9229eab46fe7e8dd8a8091f626504b394 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Fri, 14 Sep 2012 19:00:30 +0200 Subject: [PATCH 207/252] nfs4: Fix some cache revalidator problems --- .../file_systems/nfs4/CacheRevalidator.cpp | 7 +++-- .../file_systems/nfs4/CacheRevalidator.h | 6 ++-- .../file_systems/nfs4/DirectoryCache.cpp | 3 +- .../kernel/file_systems/nfs4/DirectoryCache.h | 21 +++++++------ .../kernel/file_systems/nfs4/Inode.cpp | 30 +++++++++++-------- .../kernel/file_systems/nfs4/InodeDir.cpp | 8 ++--- .../kernel/file_systems/nfs4/InodeRegular.cpp | 5 ++-- 7 files changed, 47 insertions(+), 33 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/CacheRevalidator.cpp b/src/add-ons/kernel/file_systems/nfs4/CacheRevalidator.cpp index d1abbbf4e6..a18ac71615 100644 --- a/src/add-ons/kernel/file_systems/nfs4/CacheRevalidator.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/CacheRevalidator.cpp @@ -86,8 +86,12 @@ CacheRevalidator::_DirectoryCacheRevalidator() continue; } - if (current->Lock() != B_OK) + current->Lock(); + if (!current->Valid()) { + RemoveDirectory(current); + current->Unlock(); continue; + } if (current->ExpireTime() > system_time()) { current->Unlock(); @@ -110,7 +114,6 @@ CacheRevalidator::_DirectoryCacheRevalidator() if (current->Revalidate() == B_OK) AddDirectory(current); - locker.Unlock(); current->Unlock(); } } diff --git a/src/add-ons/kernel/file_systems/nfs4/CacheRevalidator.h b/src/add-ons/kernel/file_systems/nfs4/CacheRevalidator.h index 7e1e4a7862..34d4f8a055 100644 --- a/src/add-ons/kernel/file_systems/nfs4/CacheRevalidator.h +++ b/src/add-ons/kernel/file_systems/nfs4/CacheRevalidator.h @@ -58,8 +58,10 @@ CacheRevalidator::Unlock() inline void CacheRevalidator::AddDirectory(DirectoryCache* cache) { - cache->fRevalidated = true; - fDirectoryCaches.InsertAfter(fDirectoryCaches.Tail(), cache); + if (!cache->fRevalidated) { + cache->fRevalidated = true; + fDirectoryCaches.InsertAfter(fDirectoryCaches.Tail(), cache); + } } diff --git a/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.cpp b/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.cpp index 979838655c..93ecfdec55 100644 --- a/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.cpp @@ -70,9 +70,8 @@ DirectoryCache::~DirectoryCache() void -DirectoryCache::ResetAndLock() +DirectoryCache::Reset() { - mutex_lock(&fLock); Trash(); fExpireTime = system_time() + kExpirationTime; fTrashed = false; diff --git a/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.h b/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.h index 4099950833..45b7bf3133 100644 --- a/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.h +++ b/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.h @@ -40,11 +40,12 @@ public: DirectoryCache(Inode* inode, bool attr = false); ~DirectoryCache(); - inline status_t Lock(); + inline void Lock(); inline void Unlock(); - void ResetAndLock(); + void Reset(); void Trash(); + inline bool Valid(); status_t AddEntry(const char* name, ino_t node, bool created = false); @@ -87,18 +88,13 @@ private: }; -inline status_t +inline void DirectoryCache::Lock() { mutex_lock(&fLock); - if (fTrashed) { - mutex_unlock(&fLock); - return B_ERROR; - } - - return B_OK; } + inline void DirectoryCache::Unlock() { @@ -106,6 +102,13 @@ DirectoryCache::Unlock() } +inline bool +DirectoryCache::Valid() +{ + return !fTrashed; +} + + inline DirectoryCacheSnapshot* DirectoryCache::GetSnapshot() { diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index d52409deb3..00837a5b89 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -197,8 +197,9 @@ Inode::LookUp(const char* name, ino_t* id) return result; fFileSystem->Revalidator().Lock(); - if (fCache->Lock() != B_OK) { - fCache->ResetAndLock(); + fCache->Lock(); + if (!fCache->Valid()) { + fCache->Reset(); fCache->SetChangeInfo(change); } else { fFileSystem->Revalidator().RemoveDirectory(fCache); @@ -232,15 +233,16 @@ Inode::Link(Inode* dir, const char* name) fFileSystem->InoIdMap()->AddEntry(fi, fInfo.fFileId); - if (dir->fCache->Lock() == B_OK) { + dir->fCache->Lock(); + if (dir->fCache->Valid()) { if (changeInfo.fAtomic && dir->fCache->ChangeInfo() == changeInfo.fBefore) { dir->fCache->AddEntry(name, fInfo.fFileId, true); dir->fCache->SetChangeInfo(changeInfo.fAfter); } else if (dir->fCache->ChangeInfo() != changeInfo.fBefore) dir->fCache->Trash(); - dir->fCache->Unlock(); } + dir->fCache->Unlock(); notify_entry_created(fFileSystem->DevId(), dir->ID(), name, ID()); @@ -270,15 +272,16 @@ Inode::Remove(const char* name, FileType type, ino_t* id) return result; DirectoryCache* cache = type != NF4NAMEDATTR ? fCache : fAttrCache; - if (cache->Lock() == B_OK) { + cache->Lock(); + if (cache->Valid()) { if (changeInfo.fAtomic && fCache->ChangeInfo() == changeInfo.fBefore) { cache->RemoveEntry(name); cache->SetChangeInfo(changeInfo.fAfter); } else if (cache->ChangeInfo() != changeInfo.fBefore) cache->Trash(); - cache->Unlock(); } + cache->Unlock(); fFileSystem->Root()->MakeInfoInvalid(); if (id != NULL) @@ -333,29 +336,31 @@ Inode::Rename(Inode* from, Inode* to, const char* fromName, const char* toName, from->fFileSystem->Root()->MakeInfoInvalid(); DirectoryCache* cache = attribute ? from->fAttrCache : from->fCache; - if (cache->Lock() == B_OK) { + cache->Lock(); + if (cache->Valid()) { if (fromChange.fAtomic && cache->ChangeInfo() == fromChange.fBefore) { cache->RemoveEntry(fromName); cache->SetChangeInfo(fromChange.fAfter); } else if (cache->ChangeInfo() != fromChange.fBefore) cache->Trash(); - cache->Unlock(); } + cache->Unlock(); if (id != NULL) *id = FileIdToInoT(fileID); cache = attribute ? to->fAttrCache : to->fCache; - if (cache->Lock() == B_OK) { + cache->Lock(); + if (cache->Valid()) { if (toChange.fAtomic && cache->ChangeInfo() == toChange.fBefore) { cache->AddEntry(toName, fileID, true); cache->SetChangeInfo(toChange.fAfter); } else if (to->fCache->ChangeInfo() != toChange.fBefore) cache->Trash(); - cache->Unlock(); } + cache->Unlock(); if (attribute) { notify_attribute_changed(from->fFileSystem->DevId(), from->ID(), @@ -396,14 +401,15 @@ Inode::CreateObject(const char* name, const char* path, int mode, FileType type) if (result != B_OK) return B_OK; - if (fCache->Lock() == B_OK) { + fCache->Lock(); + if (fCache->Valid()) { if (changeInfo.fAtomic && fCache->ChangeInfo() == changeInfo.fBefore) { fCache->AddEntry(name, fileID, true); fCache->SetChangeInfo(changeInfo.fAfter); } else if (fCache->ChangeInfo() != changeInfo.fBefore) fCache->Trash(); - fCache->Unlock(); } + fCache->Unlock(); notify_entry_created(fFileSystem->DevId(), ID(), name, FileIdToInoT(fileID)); diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp b/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp index 5633fba537..3627468dd2 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp @@ -302,11 +302,11 @@ Inode::ReadDir(void* _buffer, uint32 size, uint32* _count, DirectoryCache* cache = cookie->fAttrDir ? fAttrCache : fCache; if (cookie->fSnapshot == NULL) { fFileSystem->Revalidator().Lock(); - if (cache->Lock() != B_OK) { - cache->ResetAndLock(); - } else { + cache->Lock(); + if (!cache->Valid()) + cache->Reset(); + else fFileSystem->Revalidator().RemoveDirectory(cache); - } cookie->fSnapshot = cache->GetSnapshot(); if (cookie->fSnapshot == NULL) { diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp index 756d49e44d..a9243ffcbd 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp @@ -42,15 +42,16 @@ Inode::CreateState(const char* name, int mode, int perms, OpenState* state, fFileSystem->InoIdMap()->AddEntry(fi, FileIdToInoT(fileID)); - if (fCache->Lock() == B_OK) { + fCache->Lock(); + if (fCache->Valid()) { if (changeInfo.fAtomic && fCache->ChangeInfo() == changeInfo.fBefore) { fCache->AddEntry(name, fileID, true); fCache->SetChangeInfo(changeInfo.fAfter); } else if (fCache->ChangeInfo() != changeInfo.fBefore) fCache->Trash(); - fCache->Unlock(); } + fCache->Unlock(); state->fFileSystem = fFileSystem; state->fInfo = fi; From bcb18a9b361caf5ec949023dce39b831709a917d Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Wed, 31 Oct 2012 16:17:22 +0100 Subject: [PATCH 208/252] nfs4, dns_resolver: fix numerous style violations --- .../file_systems/nfs4/CacheRevalidator.h | 3 ++- .../kernel/file_systems/nfs4/Connection.cpp | 14 +++++++------- .../file_systems/nfs4/DirectoryCache.cpp | 5 +++-- .../kernel/file_systems/nfs4/FileSystem.cpp | 12 ++++++------ src/add-ons/kernel/file_systems/nfs4/Inode.cpp | 8 +++++--- src/add-ons/kernel/file_systems/nfs4/Inode.h | 4 ++-- .../kernel/file_systems/nfs4/InodeDir.cpp | 1 - .../kernel/file_systems/nfs4/InodeRegular.cpp | 8 ++++---- .../kernel/file_systems/nfs4/NFS4Defs.h | 18 +++++++++--------- .../kernel/file_systems/nfs4/NFS4Inode.cpp | 14 +++++++------- .../kernel/file_systems/nfs4/NFS4Server.cpp | 2 +- .../kernel/file_systems/nfs4/OpenState.cpp | 6 +++--- .../file_systems/nfs4/RPCCallbackRequest.cpp | 2 +- .../file_systems/nfs4/RPCCallbackRequest.h | 2 +- src/add-ons/kernel/file_systems/nfs4/RPCDefs.h | 16 ++++++++-------- .../kernel/file_systems/nfs4/RPCReply.cpp | 2 +- .../kernel/file_systems/nfs4/RPCReply.h | 2 +- .../file_systems/nfs4/ReplyInterpreter.cpp | 7 +++---- .../kernel/file_systems/nfs4/Request.cpp | 8 ++++---- .../file_systems/nfs4/RequestBuilder.cpp | 12 ++++++------ .../kernel/file_systems/nfs4/WorkQueue.cpp | 4 ++-- src/add-ons/kernel/file_systems/nfs4/XDR.cpp | 2 +- .../file_systems/nfs4/kernel_interface.cpp | 6 +++--- .../kernel_add_on/dns_resolver.cpp | 15 ++++++++------- .../network/dns_resolver/server/main.cpp | 4 ++-- 25 files changed, 90 insertions(+), 87 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/CacheRevalidator.h b/src/add-ons/kernel/file_systems/nfs4/CacheRevalidator.h index 34d4f8a055..97879b2979 100644 --- a/src/add-ons/kernel/file_systems/nfs4/CacheRevalidator.h +++ b/src/add-ons/kernel/file_systems/nfs4/CacheRevalidator.h @@ -48,6 +48,7 @@ CacheRevalidator::Lock() mutex_lock(&fDirectoryCachesLock); } + inline void CacheRevalidator::Unlock() { @@ -75,4 +76,4 @@ CacheRevalidator::RemoveDirectory(DirectoryCache* cache) #endif // CACHEREVALIDATOR_H - + diff --git a/src/add-ons/kernel/file_systems/nfs4/Connection.cpp b/src/add-ons/kernel/file_systems/nfs4/Connection.cpp index d94801b2b0..2c13915959 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Connection.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Connection.cpp @@ -34,6 +34,7 @@ PeerAddress::operator==(const PeerAddress& address) && fProtocol == address.fProtocol; } + bool PeerAddress::operator<(const PeerAddress& address) { @@ -257,7 +258,6 @@ ConnectionBase::ConnectionBase(const PeerAddress& address) } - ConnectionStream::ConnectionStream(const PeerAddress& address) : Connection(address) @@ -360,8 +360,8 @@ ConnectionStream::Receive(void** _buffer, uint32* _size) do { result = wait_for_objects(object, 2); - if (result < B_OK || - (object[0].events & B_EVENT_ACQUIRE_SEMAPHORE) != 0) { + if (result < B_OK + || (object[0].events & B_EVENT_ACQUIRE_SEMAPHORE) != 0) { free(buffer); return ECONNABORTED; } else if ((object[1].events & B_EVENT_READ) == 0) @@ -438,8 +438,8 @@ ConnectionPacket::Receive(void** _buffer, uint32* _size) do { result = wait_for_objects(object, 2); - if (result < B_OK || - (object[0].events & B_EVENT_ACQUIRE_SEMAPHORE) != 0) { + if (result < B_OK + || (object[0].events & B_EVENT_ACQUIRE_SEMAPHORE) != 0) { free(buffer); return ECONNABORTED; } else if ((object[1].events & B_EVENT_READ) == 0) @@ -695,8 +695,8 @@ ConnectionListener::AcceptConnection(Connection** connection) do { status_t result = wait_for_objects(object, 2); - if (result < B_OK || - (object[0].events & B_EVENT_ACQUIRE_SEMAPHORE) != 0) { + if (result < B_OK + || (object[0].events & B_EVENT_ACQUIRE_SEMAPHORE) != 0) { return ECONNABORTED; } else if ((object[1].events & B_EVENT_READ) == 0) continue; diff --git a/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.cpp b/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.cpp index 93ecfdec55..2fe8e61fee 100644 --- a/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.cpp @@ -128,6 +128,7 @@ DirectoryCache::AddEntry(const char* name, ino_t node, bool created) return B_OK; } + void DirectoryCache::RemoveEntry(const char* name) { @@ -244,8 +245,8 @@ DirectoryCache::NotifyChanges(DirectoryCacheSnapshot* oldSnapshot, bool found = false; NameCacheEntry* prev = NULL; while (oldCurrent != NULL) { - if (oldCurrent->fNode == newCurrent->fNode && - strcmp(oldCurrent->fName, newCurrent->fName) == 0) { + if (oldCurrent->fNode == newCurrent->fNode + && strcmp(oldCurrent->fName, newCurrent->fName) == 0) { found = true; break; } diff --git a/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp b/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp index ec5d992987..860c891e6f 100644 --- a/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp @@ -138,12 +138,12 @@ FileSystem::Mount(FileSystem** pfs, RPC::Server* serv, const char* fsPath, fs->fExpireType = values[1].fData.fValue32; // FATTR4_FSID is mandatory - FileSystemId* fsid = - reinterpret_cast(values[2].fData.fPointer); + FileSystemId* fsid + = reinterpret_cast(values[2].fData.fPointer); if (count == 4 && values[3].fAttribute == FATTR4_FS_LOCATIONS) { - FSLocations* locs = - reinterpret_cast(values[3].fData.fLocations); + FSLocations* locs + = reinterpret_cast(values[3].fData.fLocations); fs->fPath = strdup(locs->fRootPath); } else @@ -230,8 +230,8 @@ FileSystem::Migrate(const RPC::Server* serv) if (result != B_OK) return result; - FSLocations* locs = - reinterpret_cast(values[0].fData.fLocations); + FSLocations* locs + = reinterpret_cast(values[0].fData.fLocations); RPC::Server* server = fServer; PeerAddress addr = fServer->ID(); diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index 00837a5b89..2a7705403c 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -39,7 +39,7 @@ Inode::Inode() status_t -Inode::CreateInode(FileSystem* fs, const FileInfo &fi, Inode** _inode) +Inode::CreateInode(FileSystem* fs, const FileInfo& fi, Inode** _inode) { Inode* inode = NULL; if (fs->Root() == NULL) @@ -104,8 +104,8 @@ Inode::CreateInode(FileSystem* fs, const FileInfo &fi, Inode** _inode) size = values[2].fData.fValue64; // FATTR4_FSID is mandatory - FileSystemId* fsid = - reinterpret_cast(values[3].fData.fPointer); + FileSystemId* fsid + = reinterpret_cast(values[3].fData.fPointer); if (*fsid != fs->FsId()) { delete[] values; return B_ENTRY_NOT_FOUND; @@ -653,6 +653,7 @@ Inode::CheckLockType(short ltype, uint32 mode) } } + status_t Inode::TestLock(OpenFileCookie* cookie, struct flock* lock) { @@ -685,6 +686,7 @@ Inode::TestLock(OpenFileCookie* cookie, struct flock* lock) return B_OK; } + status_t Inode::AcquireLock(OpenFileCookie* cookie, const struct flock* lock, bool wait) diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h b/src/add-ons/kernel/file_systems/nfs4/Inode.h index 6a89c949e7..1201d2857e 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -82,12 +82,12 @@ public: 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); + const void* buffer, size_t* _length); status_t ReadDirect(OpenStateCookie* cookie, off_t pos, void* buffer, size_t* length, bool* eof); status_t WriteDirect(OpenStateCookie* cookie, off_t pos, - const void* buffer, size_t *_length); + const void* buffer, size_t* _length); status_t CreateDir(const char* name, int mode); status_t OpenDir(OpenDirCookie* cookie); diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp b/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp index 3627468dd2..7e374c3448 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp @@ -210,7 +210,6 @@ FileToAttrName(const char* path) } - status_t Inode::GetDirSnapshot(DirectoryCacheSnapshot** _snapshot, OpenDirCookie* cookie, uint64* _change, bool attribute) diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp index a9243ffcbd..811013fb7c 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp @@ -284,8 +284,8 @@ Inode::CloseAttr(OpenAttrCookie* cookie) status_t -Inode::ReadDirect(OpenStateCookie* cookie, off_t pos, void* buffer, size_t* _length, - bool* eof) +Inode::ReadDirect(OpenStateCookie* cookie, off_t pos, void* buffer, + size_t* _length, bool* eof) { *eof = false; uint32 size = 0; @@ -327,7 +327,7 @@ Inode::Read(OpenFileCookie* cookie, off_t pos, void* buffer, size_t* _length) status_t Inode::WriteDirect(OpenStateCookie* cookie, off_t pos, const void* _buffer, - size_t *_length) + size_t* _length) { uint32 size = 0; const char* buffer = reinterpret_cast(_buffer); @@ -370,7 +370,7 @@ Inode::WriteDirect(OpenStateCookie* cookie, off_t pos, const void* _buffer, status_t Inode::Write(OpenFileCookie* cookie, off_t pos, const void* _buffer, - size_t *_length) + size_t* _length) { struct stat st; status_t result = Stat(&st); diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h index 236d37742f..aab14e6596 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h @@ -153,15 +153,15 @@ static inline bool sIsAttrSet(Attribute attr, const uint32* bitmap, enum FileType { - NF4REG = 1, /* Regular File */ - NF4DIR = 2, /* Directory */ - NF4BLK = 3, /* Special File - block device */ - NF4CHR = 4, /* Special File - character device */ - NF4LNK = 5, /* Symbolic Link */ - NF4SOCK = 6, /* Special File - socket */ - NF4FIFO = 7, /* Special File - fifo */ - NF4ATTRDIR = 8, /* Attribute Directory */ - NF4NAMEDATTR = 9 /* Named Attribute */ + NF4REG = 1, /* Regular File */ + NF4DIR = 2, /* Directory */ + NF4BLK = 3, /* Special File - block device */ + NF4CHR = 4, /* Special File - character device */ + NF4LNK = 5, /* Symbolic Link */ + NF4SOCK = 6, /* Special File - socket */ + NF4FIFO = 7, /* Special File - fifo */ + NF4ATTRDIR = 8, /* Attribute Directory */ + NF4NAMEDATTR = 9 /* Named Attribute */ }; static const mode_t sNFSFileTypeToHaiku[] = { diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp index dd590085fa..73d176bc6f 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp @@ -173,8 +173,8 @@ NFS4Inode::LookUp(const char* name, uint64* change, uint64* fileID, return result; // FATTR4_FSID is mandatory - FileSystemId* fsid = - reinterpret_cast(values[0].fData.fPointer); + FileSystemId* fsid + = reinterpret_cast(values[0].fData.fPointer); if (*fsid != fFileSystem->FsId()) { delete[] values; return B_ENTRY_NOT_FOUND; @@ -562,8 +562,8 @@ NFS4Inode::OpenFile(OpenState* state, int mode, OpenDelegationData* delegation) // Verify if the file we want to open is the file this Inode // represents. - if (fFileSystem->IsAttrSupported(FATTR4_FILEID) || - fFileSystem->ExpireType() == FH4_PERSISTENT) { + if (fFileSystem->IsAttrSupported(FATTR4_FILEID) + || fFileSystem->ExpireType() == FH4_PERSISTENT) { reply.PutFH(); result = reply.LookUp(); if (result != B_OK) { @@ -1004,7 +1004,7 @@ NFS4Inode::TestLock(OpenFileCookie* cookie, LockType* type, uint64* position, if (result != B_OK) return result; - ReplyInterpreter &reply = request.Reply(); + ReplyInterpreter& reply = request.Reply(); if (HandleErrors(reply.NFS4Error(), serv, cookie)) continue; @@ -1043,7 +1043,7 @@ NFS4Inode::AcquireLock(OpenFileCookie* cookie, LockInfo* lockInfo, bool wait) return result; } - ReplyInterpreter &reply = request.Reply(); + ReplyInterpreter& reply = request.Reply(); sequence += IncrementSequence(reply.NFS4Error()); @@ -1087,7 +1087,7 @@ NFS4Inode::ReleaseLock(OpenFileCookie* cookie, LockInfo* lockInfo) if (result != B_OK) return result; - ReplyInterpreter &reply = request.Reply(); + ReplyInterpreter& reply = request.Reply(); reply.PutFH(); result = reply.LockU(lockInfo); diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp index 8a39021bd8..c7f5ee285c 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp @@ -209,7 +209,7 @@ NFS4Server::_StartRenewing() fThreadCancel = false; fThread = spawn_kernel_thread(&NFS4Server::_RenewalThreadStart, - "NFSv4 Renewal", B_NORMAL_PRIORITY, this); + "NFSv4 Renewal", B_NORMAL_PRIORITY, this); if (fThread < B_OK) return fThread; diff --git a/src/add-ons/kernel/file_systems/nfs4/OpenState.cpp b/src/add-ons/kernel/file_systems/nfs4/OpenState.cpp index 1655c79170..c02ffb0d74 100644 --- a/src/add-ons/kernel/file_systems/nfs4/OpenState.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/OpenState.cpp @@ -123,7 +123,7 @@ OpenState::_ReleaseLockOwner(LockOwner* owner) if (result != B_OK) return result; - ReplyInterpreter &reply = request.Reply(); + ReplyInterpreter& reply = request.Reply(); if (HandleErrors(reply.NFS4Error(), server)) continue; @@ -191,7 +191,7 @@ OpenState::_ReclaimOpen(uint64 newClientID) result = reply.Open(fStateID, &fStateSeq, &confirm, &delegation); if (result != B_OK) { - fFileSystem->OpenOwnerSequenceUnlock(sequence); + fFileSystem->OpenOwnerSequenceUnlock(sequence); return result; } @@ -241,7 +241,7 @@ OpenState::_ReclaimLocks(uint64 newClientID) if (result != B_OK) break; - ReplyInterpreter &reply = request.Reply(); + ReplyInterpreter& reply = request.Reply(); if (HandleErrors(reply.NFS4Error(), server)) continue; diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCCallbackRequest.cpp b/src/add-ons/kernel/file_systems/nfs4/RPCCallbackRequest.cpp index 90fce4d550..7ed177326e 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RPCCallbackRequest.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RPCCallbackRequest.cpp @@ -18,7 +18,7 @@ using namespace RPC; -CallbackRequest::CallbackRequest(void *buffer, int size) +CallbackRequest::CallbackRequest(void* buffer, int size) : fError(B_BAD_VALUE), fRPCError(GARBAGE_ARGS), diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCCallbackRequest.h b/src/add-ons/kernel/file_systems/nfs4/RPCCallbackRequest.h index 01518f3b6c..19e2e006c5 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RPCCallbackRequest.h +++ b/src/add-ons/kernel/file_systems/nfs4/RPCCallbackRequest.h @@ -17,7 +17,7 @@ namespace RPC { class CallbackRequest { public: - CallbackRequest(void *buffer, int size); + CallbackRequest(void* buffer, int size); ~CallbackRequest(); inline uint32 XID(); diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCDefs.h b/src/add-ons/kernel/file_systems/nfs4/RPCDefs.h index bd551a69b5..3363eaeb66 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RPCDefs.h +++ b/src/add-ons/kernel/file_systems/nfs4/RPCDefs.h @@ -36,17 +36,17 @@ enum { }; enum AcceptStat { - SUCCESS = 0, /* RPC executed successfully */ - PROG_UNAVAIL = 1, /* remote hasn't exported program */ - PROG_MISMATCH = 2, /* remote can't support version # */ - PROC_UNAVAIL = 3, /* program can't support procedure */ - GARBAGE_ARGS = 4, /* procedure can't decode params */ - SYSTEM_ERR = 5 /* e.g. memory allocation failure */ + SUCCESS = 0, /* RPC executed successfully */ + PROG_UNAVAIL = 1, /* remote hasn't exported program */ + PROG_MISMATCH = 2, /* remote can't support version # */ + PROC_UNAVAIL = 3, /* program can't support procedure */ + GARBAGE_ARGS = 4, /* procedure can't decode params */ + SYSTEM_ERR = 5 /* e.g. memory allocation failure */ }; enum RejectStat { - RPC_MISMATCH = 0, /* RPC version number != 2 */ - AUTH_ERROR = 1 /* remote can't authenticate caller */ + RPC_MISMATCH = 0, /* RPC version number != 2 */ + AUTH_ERROR = 1 /* remote can't authenticate caller */ }; enum AuthFlavour { diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCReply.cpp b/src/add-ons/kernel/file_systems/nfs4/RPCReply.cpp index 3f61357e09..4166d4e24c 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RPCReply.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RPCReply.cpp @@ -17,7 +17,7 @@ using namespace RPC; -Reply::Reply(void *buffer, int size) +Reply::Reply(void* buffer, int size) : fError(B_OK), fStream(buffer, size), diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCReply.h b/src/add-ons/kernel/file_systems/nfs4/RPCReply.h index 6d688d89bf..50a200b3b8 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RPCReply.h +++ b/src/add-ons/kernel/file_systems/nfs4/RPCReply.h @@ -16,7 +16,7 @@ namespace RPC { class Reply { public: - Reply(void *buffer, int size); + Reply(void* buffer, int size); ~Reply(); inline uint32 GetXID(); diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp index 4ed2023277..14b8df860a 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp @@ -158,7 +158,6 @@ ReplyInterpreter::Create(uint64* before, uint64* after, bool& atomic) } - // Bit Twiddling Hacks // http://graphics.stanford.edu/~seander/bithacks.html static inline uint32 CountBits(uint32 v) @@ -555,7 +554,7 @@ ReplyInterpreter::_DecodeAttrs(XDR::ReadStream& str, AttrValue** attrs, uint32* count) { uint32 bcount = fReply->Stream().GetUInt(); - uint32 *bitmap = new(std::nothrow) uint32[bcount]; + uint32* bitmap = new(std::nothrow) uint32[bcount]; if (bitmap == NULL) return B_NO_MEMORY; @@ -667,8 +666,8 @@ ReplyInterpreter::_DecodeAttrs(XDR::ReadStream& str, AttrValue** attrs, for (uint32 i = 0; i < locs->fCount; i++) { locs->fLocations[i].fRootPath = sFlattenPathname(stream); locs->fLocations[i].fCount = stream.GetUInt(); - locs->fLocations[i].fLocations = - new const char*[locs->fLocations[i].fCount]; + locs->fLocations[i].fLocations + = new const char*[locs->fLocations[i].fCount]; for (uint32 j = 0; j < locs->fLocations[i].fCount; j++) locs->fLocations[i].fLocations[j] = stream.GetString(); } diff --git a/src/add-ons/kernel/file_systems/nfs4/Request.cpp b/src/add-ons/kernel/file_systems/nfs4/Request.cpp index d68d5b2176..3924f3bc03 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Request.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Request.cpp @@ -28,8 +28,8 @@ Request::Send(Cookie* cookie) status_t Request::_SendUDP(Cookie* cookie) { - RPC::Reply *rpl = NULL; - RPC::Request *rpc; + RPC::Reply* rpl = NULL; + RPC::Request* rpc; status_t result = fServer->SendCallAsync(fBuilder.Request(), &rpl, &rpc); if (result != B_OK) @@ -87,8 +87,8 @@ Request::_SendUDP(Cookie* cookie) status_t Request::_SendTCP(Cookie* cookie) { - RPC::Reply *rpl = NULL; - RPC::Request *rpc; + RPC::Reply* rpl = NULL; + RPC::Request* rpc; status_t result; int attempts = 0; diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp index 306e680aa8..3b8f69e376 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp @@ -837,8 +837,8 @@ RequestBuilder::_EncodeAttrs(XDR::WriteStream& stream, AttrValue* attr, return; } - Attribute* attrs = - reinterpret_cast(malloc(sizeof(Attribute) * count)); + Attribute* attrs + = reinterpret_cast(malloc(sizeof(Attribute) * count)); for (uint32 i = 0; i < count; i++) attrs[i] = static_cast(attr[i].fAttribute); _AttrBitmap(stream, attrs, count); @@ -885,8 +885,8 @@ RequestBuilder::_EncodeAttrs(XDR::WriteStream& stream, AttrValue* attr, if (i < count && attr[i].fAttribute == FATTR4_TIME_ACCESS_SET) { str.AddInt(1); // SET_TO_CLIENT_TIME4 - struct timespec* ts = - reinterpret_cast(attr[i].fData.fPointer); + struct timespec* ts + = reinterpret_cast(attr[i].fData.fPointer); str.AddHyper(ts->tv_sec); str.AddUInt(ts->tv_nsec); @@ -896,8 +896,8 @@ RequestBuilder::_EncodeAttrs(XDR::WriteStream& stream, AttrValue* attr, if (i < count && attr[i].fAttribute == FATTR4_TIME_MODIFY_SET) { str.AddInt(1); // SET_TO_CLIENT_TIME4 - struct timespec* ts = - reinterpret_cast(attr[i].fData.fPointer); + struct timespec* ts + = reinterpret_cast(attr[i].fData.fPointer); str.AddHyper(ts->tv_sec); str.AddUInt(ts->tv_nsec); diff --git a/src/add-ons/kernel/file_systems/nfs4/WorkQueue.cpp b/src/add-ons/kernel/file_systems/nfs4/WorkQueue.cpp index c576b96896..9a19120966 100644 --- a/src/add-ons/kernel/file_systems/nfs4/WorkQueue.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/WorkQueue.cpp @@ -94,8 +94,8 @@ WorkQueue::WorkingThread() status_t result = wait_for_objects(object, 2); - if (result < B_OK || - (object[0].events & B_EVENT_ACQUIRE_SEMAPHORE) != 0) { + if (result < B_OK + || (object[0].events & B_EVENT_ACQUIRE_SEMAPHORE) != 0) { return result; } else if ((object[1].events & B_EVENT_ACQUIRE_SEMAPHORE) == 0) continue; diff --git a/src/add-ons/kernel/file_systems/nfs4/XDR.cpp b/src/add-ons/kernel/file_systems/nfs4/XDR.cpp index 9cc116d393..86a6462525 100644 --- a/src/add-ons/kernel/file_systems/nfs4/XDR.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/XDR.cpp @@ -277,7 +277,7 @@ WriteStream::AddString(const char* str, uint32 maxlen) status_t -WriteStream::AddOpaque(const void *ptr, uint32 size) +WriteStream::AddOpaque(const void* ptr, uint32 size) { uint32 real_size = _RealSize(size); status_t err = _CheckResize(real_size + sizeof(uint32)); 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 9958fa02e6..861b14d9dd 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -132,13 +132,13 @@ nfs4_mount(fs_volume* volume, const char* device, uint32 flags, PeerAddress address; MountConfiguration config; - char *path; + char* path; result = ParseArguments(args, &address, &path, &config); if (result != B_OK) return result; MemoryDeleter pathDeleter(path); - RPC::Server *server; + RPC::Server* server; result = gRPCServerManager->Acquire(&server, address, CreateNFS4Server); if (result != B_OK) return result; @@ -1065,7 +1065,7 @@ static file_system_module_info sNFSv4ModuleInfo = { }; module_info* modules[] = { - (module_info* )&sNFSv4ModuleInfo, + (module_info*)&sNFSv4ModuleInfo, NULL, }; diff --git a/src/add-ons/kernel/network/dns_resolver/kernel_add_on/dns_resolver.cpp b/src/add-ons/kernel/network/dns_resolver/kernel_add_on/dns_resolver.cpp index 6c1e0c9872..476b3948fd 100644 --- a/src/add-ons/kernel/network/dns_resolver/kernel_add_on/dns_resolver.cpp +++ b/src/add-ons/kernel/network/dns_resolver/kernel_add_on/dns_resolver.cpp @@ -105,16 +105,16 @@ RelocateEntries(struct addrinfo* addr) uint64 nextOffset = reinterpret_cast(current->ai_next); if (current->ai_addr != NULL) { - current->ai_addr = - reinterpret_cast(generalOffset + addrOffset); + current->ai_addr + = reinterpret_cast(generalOffset + addrOffset); } if (current->ai_canonname != NULL) current->ai_canonname = generalOffset + nameOffset; if (current->ai_next != NULL) { - current->ai_next = - reinterpret_cast(generalOffset + nextOffset); + current->ai_next + = reinterpret_cast(generalOffset + nextOffset); } current = current->ai_next; @@ -150,8 +150,8 @@ GetAddrInfo(const char* node, const char* service, if (hints != NULL) memcpy(buffer + off, hints, sizeof(*hints)); else { - struct addrinfo *nullHints = - reinterpret_cast(buffer + off); + struct addrinfo *nullHints + = reinterpret_cast(buffer + off); memset(nullHints, 0, sizeof(*nullHints)); nullHints->ai_family = AF_UNSPEC; } @@ -190,7 +190,7 @@ GetAddrInfo(const char* node, const char* service, continue; } - struct addrinfo *addr; + struct addrinfo* addr; switch (code) { case MsgReply: addr = reinterpret_cast(reply); @@ -223,6 +223,7 @@ dns_resolver_std_ops(int32 op, ...) } } + static dns_resolver_module sDNSResolverModule = { { DNS_RESOLVER_MODULE_NAME, diff --git a/src/add-ons/kernel/network/dns_resolver/server/main.cpp b/src/add-ons/kernel/network/dns_resolver/server/main.cpp index 8082488f5a..c5519fe1a9 100644 --- a/src/add-ons/kernel/network/dns_resolver/server/main.cpp +++ b/src/add-ons/kernel/network/dns_resolver/server/main.cpp @@ -33,8 +33,8 @@ GetAddrInfo(const char* buffer) const char* service = buffer[nodeSize] == '\0' ? NULL : buffer + nodeSize; uint32 serviceSize = service != NULL ? strlen(service) + 1 : 1; - const struct addrinfo* hints = - reinterpret_cast(buffer + nodeSize + serviceSize); + const struct addrinfo* hints + = reinterpret_cast(buffer + nodeSize + serviceSize); struct addrinfo* ai; status_t result = getaddrinfo(node, service, hints, &ai); From a4cdd6be5fb0a4b2a6f548be451611f3b959fb1c Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Wed, 31 Oct 2012 18:57:17 +0100 Subject: [PATCH 209/252] dns_resolver: Separate getaddrinfo() and reply serialization code --- .../network/dns_resolver/server/main.cpp | 72 ++++++++++++------- 1 file changed, 45 insertions(+), 27 deletions(-) diff --git a/src/add-ons/kernel/network/dns_resolver/server/main.cpp b/src/add-ons/kernel/network/dns_resolver/server/main.cpp index c5519fe1a9..f82d405427 100644 --- a/src/add-ons/kernel/network/dns_resolver/server/main.cpp +++ b/src/add-ons/kernel/network/dns_resolver/server/main.cpp @@ -25,27 +25,13 @@ port_id gReplyPort; status_t -GetAddrInfo(const char* buffer) +Serialize(char** _reply, uint32* _totalSize, const struct addrinfo* ai) { - const char* node = buffer[0] == '\0' ? NULL : buffer; - uint32 nodeSize = node != NULL ? strlen(node) + 1 : 1; - - const char* service = buffer[nodeSize] == '\0' ? NULL : buffer + nodeSize; - uint32 serviceSize = service != NULL ? strlen(service) + 1 : 1; - - const struct addrinfo* hints - = reinterpret_cast(buffer + nodeSize + serviceSize); - - struct addrinfo* ai; - status_t result = getaddrinfo(node, service, hints, &ai); - if (result != B_OK) - return write_port(gReplyPort, MsgError, &result, sizeof(result)); - uint32 addrsSize = ai == NULL ? 0 : sizeof(addrinfo); uint32 namesSize = 0; uint32 socksSize = 0; - addrinfo* current = ai; + const struct addrinfo* current = ai; while (current != NULL) { if (current->ai_canonname != NULL) namesSize += strlen(current->ai_canonname) + 1; @@ -62,46 +48,78 @@ GetAddrInfo(const char* buffer) uint32 totalSize = addrsSize + namesSize + socksSize; char* reply = reinterpret_cast(malloc(totalSize)); - if (reply == NULL) { - free(reply); - - result = B_NO_MEMORY; - return write_port(gReplyPort, MsgError, &result, sizeof(result)); - } + if (reply == NULL) + return B_NO_MEMORY; uint32 addrPos = 0; uint32 namePos = addrsSize; uint32 sockPos = addrsSize + namesSize; + struct addrinfo temp; + current = ai; while (current != NULL) { + memcpy(&temp, current, sizeof(addrinfo)); + if (current->ai_canonname != NULL) { strcpy(reply + namePos, current->ai_canonname); uint32 nSize = strlen(current->ai_canonname) + 1; - current->ai_canonname = reinterpret_cast(namePos); + temp.ai_canonname = reinterpret_cast(namePos); namePos += nSize; } if (current->ai_addr != NULL) { if (current->ai_family == AF_INET) { memcpy(reply + sockPos, current->ai_addr, sizeof(sockaddr_in)); - current->ai_addr = reinterpret_cast(sockPos); + temp.ai_addr = reinterpret_cast(sockPos); sockPos += sizeof(sockaddr_in); } else { memcpy(reply + sockPos, current->ai_addr, sizeof(sockaddr_in6)); - current->ai_addr = reinterpret_cast(sockPos); + temp.ai_addr = reinterpret_cast(sockPos); sockPos += sizeof(sockaddr_in6); } } addrinfo* next = current->ai_next; if (next != NULL) - current->ai_next = reinterpret_cast(addrPos) + 1; - memcpy(reply + addrPos, current, sizeof(addrinfo)); + temp.ai_next = reinterpret_cast(addrPos) + 1; + else + temp.ai_next = NULL; + + memcpy(reply + addrPos, &temp, sizeof(addrinfo)); addrPos += sizeof(addrinfo); current = next; } + *_reply = reply; + *_totalSize = totalSize; + return B_OK; +} + + +status_t +GetAddrInfo(const char* buffer) +{ + const char* node = buffer[0] == '\0' ? NULL : buffer; + uint32 nodeSize = node != NULL ? strlen(node) + 1 : 1; + + const char* service = buffer[nodeSize] == '\0' ? NULL : buffer + nodeSize; + uint32 serviceSize = service != NULL ? strlen(service) + 1 : 1; + + const struct addrinfo* hints + = reinterpret_cast(buffer + nodeSize + serviceSize); + + struct addrinfo* ai; + status_t result = getaddrinfo(node, service, hints, &ai); + if (result != B_OK) + return write_port(gReplyPort, MsgError, &result, sizeof(result)); + + uint32 totalSize; + char* reply; + result = Serialize(&reply, &totalSize, ai); + freeaddrinfo(ai); + if (result != B_OK) + return write_port(gReplyPort, MsgError, &result, sizeof(result)); return write_port(gReplyPort, MsgReply, reply, totalSize); } From bb0355263687491aa7abe5a54bfd98e35fc3665d Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Mon, 27 Aug 2012 23:10:16 +0300 Subject: [PATCH 210/252] nfs4: Do not ignore idmapper initialization errors --- .../kernel/file_systems/nfs4/IdMap.cpp | 2 +- src/add-ons/kernel/file_systems/nfs4/IdMap.h | 39 ++++++++++++------- .../file_systems/nfs4/kernel_interface.cpp | 8 ++++ 3 files changed, 34 insertions(+), 15 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/IdMap.cpp b/src/add-ons/kernel/file_systems/nfs4/IdMap.cpp index 3a87315fb5..2eef09dcfa 100644 --- a/src/add-ons/kernel/file_systems/nfs4/IdMap.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/IdMap.cpp @@ -23,7 +23,7 @@ mutex gIdMapperLock; IdMap::IdMap() { mutex_init(&fLock, NULL); - _Repair(); + fInitStatus = _Repair(); } diff --git a/src/add-ons/kernel/file_systems/nfs4/IdMap.h b/src/add-ons/kernel/file_systems/nfs4/IdMap.h index 318f6dd777..fd89682364 100644 --- a/src/add-ons/kernel/file_systems/nfs4/IdMap.h +++ b/src/add-ons/kernel/file_systems/nfs4/IdMap.h @@ -16,30 +16,41 @@ class IdMap { public: - IdMap(); - ~IdMap(); + IdMap(); + ~IdMap(); - uid_t GetUserId(const char* owner); - gid_t GetGroupId(const char* ownerGroup); + uid_t GetUserId(const char* owner); + gid_t GetGroupId(const char* ownerGroup); - char* GetOwner(uid_t user); - char* GetOwnerGroup(gid_t group); + char* GetOwner(uid_t user); + char* GetOwnerGroup(gid_t group); + + inline status_t InitStatus(); private: - status_t _Repair(); + status_t _Repair(); - template - void* _GetBuffer(T value, int32 code); + template + void* _GetBuffer(T value, int32 code); - template - T _GetValue(const char* buffer, int32 code); + template + T _GetValue(const char* buffer, int32 code); - mutex fLock; + status_t fInitStatus; - port_id fRequestPort; - port_id fReplyPort; + mutex fLock; + + port_id fRequestPort; + port_id fReplyPort; }; + +inline status_t +IdMap::InitStatus() +{ + return fInitStatus; +} + extern IdMap* gIdMapper; extern mutex gIdMapperLock; 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 861b14d9dd..636d3c5965 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -124,10 +124,18 @@ nfs4_mount(fs_volume* volume, const char* device, uint32 flags, { status_t result; + /* prepare idmapper server */ MutexLocker locker(gIdMapperLock); gIdMapper = new(std::nothrow) IdMap; if (gIdMapper == NULL) return B_NO_MEMORY; + + result = gIdMapper->InitStatus(); + if (result != B_OK) { + delete gIdMapper; + gIdMapper = NULL; + return result; + } locker.Unlock(); PeerAddress address; From 1e67a2cdd9414d6f699f253161d19d4aa8fe35e6 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Wed, 31 Oct 2012 21:34:54 +0100 Subject: [PATCH 211/252] nfs4: Add numerous assertion checks --- .../file_systems/nfs4/CacheRevalidator.cpp | 2 + .../file_systems/nfs4/CacheRevalidator.h | 4 + .../kernel/file_systems/nfs4/Connection.cpp | 37 ++++++++-- .../kernel/file_systems/nfs4/Cookie.cpp | 11 ++- .../kernel/file_systems/nfs4/Delegation.cpp | 1 + .../file_systems/nfs4/DirectoryCache.cpp | 10 +++ .../kernel/file_systems/nfs4/FileInfo.cpp | 6 ++ .../kernel/file_systems/nfs4/FileSystem.cpp | 23 +++++- .../kernel/file_systems/nfs4/FileSystem.h | 3 + .../kernel/file_systems/nfs4/IdMap.cpp | 4 + .../kernel/file_systems/nfs4/Inode.cpp | 41 +++++++++++ src/add-ons/kernel/file_systems/nfs4/Inode.h | 2 + .../kernel/file_systems/nfs4/InodeDir.cpp | 17 +++++ .../kernel/file_systems/nfs4/InodeIdMap.h | 2 + .../kernel/file_systems/nfs4/InodeRegular.cpp | 36 +++++++++ .../file_systems/nfs4/MetadataCache.cpp | 8 ++ .../kernel/file_systems/nfs4/NFS4Inode.cpp | 73 +++++++++++++++++++ .../kernel/file_systems/nfs4/NFS4Object.cpp | 3 + .../kernel/file_systems/nfs4/NFS4Server.cpp | 16 ++++ .../kernel/file_systems/nfs4/OpenState.cpp | 2 + .../kernel/file_systems/nfs4/RPCCall.cpp | 4 + .../kernel/file_systems/nfs4/RPCCallback.cpp | 2 + .../file_systems/nfs4/RPCCallbackRequest.cpp | 4 + .../file_systems/nfs4/RPCCallbackServer.cpp | 14 ++++ .../kernel/file_systems/nfs4/RPCReply.cpp | 3 + .../kernel/file_systems/nfs4/RPCServer.cpp | 28 +++++++ .../kernel/file_systems/nfs4/Request.h | 1 + .../kernel/file_systems/nfs4/RootInode.cpp | 5 ++ .../kernel/file_systems/nfs4/RootInode.h | 2 + .../kernel/file_systems/nfs4/WorkQueue.cpp | 6 ++ .../file_systems/nfs4/kernel_interface.cpp | 1 + 31 files changed, 362 insertions(+), 9 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/CacheRevalidator.cpp b/src/add-ons/kernel/file_systems/nfs4/CacheRevalidator.cpp index a18ac71615..5391c1264e 100644 --- a/src/add-ons/kernel/file_systems/nfs4/CacheRevalidator.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/CacheRevalidator.cpp @@ -59,6 +59,8 @@ CacheRevalidator::_StartRevalidator() status_t CacheRevalidator::_DirectoryRevalidatorStart(void* object) { + ASSERT(object != NULL); + CacheRevalidator* revalidator = reinterpret_cast(object); revalidator->_DirectoryCacheRevalidator(); return B_OK; diff --git a/src/add-ons/kernel/file_systems/nfs4/CacheRevalidator.h b/src/add-ons/kernel/file_systems/nfs4/CacheRevalidator.h index 97879b2979..a4764dcdbf 100644 --- a/src/add-ons/kernel/file_systems/nfs4/CacheRevalidator.h +++ b/src/add-ons/kernel/file_systems/nfs4/CacheRevalidator.h @@ -59,6 +59,8 @@ CacheRevalidator::Unlock() inline void CacheRevalidator::AddDirectory(DirectoryCache* cache) { + ASSERT(cache != NULL); + if (!cache->fRevalidated) { cache->fRevalidated = true; fDirectoryCaches.InsertAfter(fDirectoryCaches.Tail(), cache); @@ -69,6 +71,8 @@ CacheRevalidator::AddDirectory(DirectoryCache* cache) inline void CacheRevalidator::RemoveDirectory(DirectoryCache* cache) { + ASSERT(cache != NULL); + if (cache->fRevalidated == true) fDirectoryCaches.Remove(cache); cache->fRevalidated = false; diff --git a/src/add-ons/kernel/file_systems/nfs4/Connection.cpp b/src/add-ons/kernel/file_systems/nfs4/Connection.cpp index 2c13915959..70eb4fe20d 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Connection.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Connection.cpp @@ -15,6 +15,7 @@ #include #include +#include #include #include @@ -81,6 +82,8 @@ PeerAddress::ProtocolString() const void PeerAddress::SetProtocol(const char* protocol) { + ASSERT(protocol != NULL); + if (strcmp(protocol, "tcp") == 0) fProtocol = IPPROTO_TCP; else if (strcmp(protocol, "udp") == 0) @@ -189,6 +192,9 @@ PeerAddress::InAddrSize() const status_t PeerAddress::ResolveName(const char* name, PeerAddress* address) { + ASSERT(name != NULL); + ASSERT(address != NULL); + address->fProtocol = IPPROTO_TCP; // getaddrinfo() is very expensive when called from kernel, so we do not @@ -284,6 +290,8 @@ ConnectionBase::~ConnectionBase() status_t ConnectionBase::GetLocalAddress(PeerAddress* address) { + ASSERT(address != NULL); + address->fProtocol = fPeerAddress.fProtocol; socklen_t addressSize = sizeof(address->fAddress); @@ -295,11 +303,14 @@ ConnectionBase::GetLocalAddress(PeerAddress* address) status_t ConnectionStream::Send(const void* buffer, uint32 size) { + ASSERT(buffer != NULL); + status_t result; - uint32* buf = (uint32*)malloc(size + sizeof(uint32)); + uint32* buf = reinterpret_cast(malloc(size + sizeof(uint32))); if (buf == NULL) return B_NO_MEMORY; + MemoryDeleter _(buf); buf[0] = htonl(size | LAST_FRAGMENT); memcpy(buf + 1, buffer, size); @@ -315,14 +326,10 @@ ConnectionStream::Send(const void* buffer, uint32 size) mutex_unlock(&fSocketLock); if (result < 0) { result = errno; - free(buf); return result; - } else if (result == 0) { - free(buf); + } else if (result == 0) return B_IO_ERROR; - } - free(buf); return B_OK; } @@ -330,6 +337,9 @@ ConnectionStream::Send(const void* buffer, uint32 size) status_t ConnectionPacket::Send(const void* buffer, uint32 size) { + ASSERT(buffer != NULL); + ASSERT(size < 65535); + // send on DGRAM sockets is atomic. No need to lock. status_t result = send(fSocket, buffer, size, 0); if (result < 0) @@ -341,6 +351,9 @@ ConnectionPacket::Send(const void* buffer, uint32 size) status_t ConnectionStream::Receive(void** _buffer, uint32* _size) { + ASSERT(_buffer != NULL); + ASSERT(_size != NULL); + status_t result; uint32 size = 0; @@ -420,6 +433,9 @@ ConnectionStream::Receive(void** _buffer, uint32* _size) status_t ConnectionPacket::Receive(void** _buffer, uint32* _size) { + ASSERT(_buffer != NULL); + ASSERT(_size != NULL); + status_t result; int32 size = MAX_PACKET_SIZE; void* buffer = malloc(size); @@ -482,6 +498,8 @@ Connection::CreateObject(const PeerAddress& address) status_t Connection::Connect(Connection **_connection, const PeerAddress& address) { + ASSERT(_connection != NULL); + Connection* conn = CreateObject(address); if (conn == NULL) return B_NO_MEMORY; @@ -509,6 +527,9 @@ status_t Connection::SetTo(Connection **_connection, int socket, const PeerAddress& address) { + ASSERT(_connection != NULL); + ASSERT(socket != -1); + Connection* conn = CreateObject(address); if (conn == NULL) return B_NO_MEMORY; @@ -637,6 +658,8 @@ ConnectionBase::Disconnect() status_t ConnectionListener::Listen(ConnectionListener** listener, uint16 port) { + ASSERT(listener != NULL); + int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (sock < 0) return errno; @@ -684,6 +707,8 @@ ConnectionListener::Listen(ConnectionListener** listener, uint16 port) status_t ConnectionListener::AcceptConnection(Connection** connection) { + ASSERT(connection != NULL); + object_wait_info object[2]; object[0].object = fWaitCancel; object[0].type = B_OBJECT_TYPE_SEMAPHORE; diff --git a/src/add-ons/kernel/file_systems/nfs4/Cookie.cpp b/src/add-ons/kernel/file_systems/nfs4/Cookie.cpp index 805721a153..e756e75301 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Cookie.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Cookie.cpp @@ -36,6 +36,7 @@ LockInfo::LockInfo(LockOwner* owner) : fOwner(owner) { + ASSERT(owner != NULL); fOwner->fUseCount++; } @@ -86,6 +87,8 @@ Cookie::~Cookie() status_t Cookie::RegisterRequest(RPC::Request* req) { + ASSERT(req != NULL); + RequestEntry* ent = new RequestEntry; if (ent == NULL) return B_NO_MEMORY; @@ -102,6 +105,8 @@ Cookie::RegisterRequest(RPC::Request* req) status_t Cookie::UnregisterRequest(RPC::Request* req) { + ASSERT(req != NULL); + MutexLocker _(fRequestLock); RequestEntry* ent = fRequests; RequestEntry* prev = NULL; @@ -148,6 +153,8 @@ OpenFileCookie::OpenFileCookie() void OpenFileCookie::AddLock(LockInfo* lock) { + ASSERT(lock != NULL); + lock->fCookieNext = fLocks; fLocks = lock; } @@ -158,8 +165,10 @@ OpenFileCookie::RemoveLock(LockInfo* lock, LockInfo* prev) { if (prev != NULL) prev->fCookieNext = lock->fCookieNext; - else + else { + ASSERT(prev == NULL && fLocks == lock); fLocks = lock->fCookieNext; + } } diff --git a/src/add-ons/kernel/file_systems/nfs4/Delegation.cpp b/src/add-ons/kernel/file_systems/nfs4/Delegation.cpp index bf2b33a11f..2fce4fde6c 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Delegation.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Delegation.cpp @@ -21,6 +21,7 @@ Delegation::Delegation(const OpenDelegationData& data, Inode* inode, fInode(inode), fAttribute(attribute) { + ASSERT(inode != NULL); } diff --git a/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.cpp b/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.cpp index 2fe8e61fee..8585f8163d 100644 --- a/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.cpp @@ -21,6 +21,7 @@ NameCacheEntry::NameCacheEntry(const char* name, ino_t node) fNode(node), fName(strdup(name)) { + ASSERT(name != NULL); } @@ -55,6 +56,8 @@ DirectoryCache::DirectoryCache(Inode* inode, bool attr) fAttrDir(attr), fTrashed(true) { + ASSERT(inode != NULL); + mutex_init(&fLock, NULL); } @@ -97,6 +100,8 @@ DirectoryCache::Trash() status_t DirectoryCache::AddEntry(const char* name, ino_t node, bool created) { + ASSERT(name != NULL); + NameCacheEntry* entry = new(std::nothrow) NameCacheEntry(name, node); if (entry == NULL) return B_NO_MEMORY; @@ -132,6 +137,8 @@ DirectoryCache::AddEntry(const char* name, ino_t node, bool created) void DirectoryCache::RemoveEntry(const char* name) { + ASSERT(name != NULL); + SinglyLinkedList::Iterator iterator = fNameCache.GetIterator(); NameCacheEntry* previous = NULL; @@ -229,6 +236,9 @@ void DirectoryCache::NotifyChanges(DirectoryCacheSnapshot* oldSnapshot, DirectoryCacheSnapshot* newSnapshot) { + ASSERT(newSnapshot != NULL); + ASSERT(oldSnapshot != NULL); + MutexLocker _(newSnapshot->fLock); SinglyLinkedList::Iterator oldIt diff --git a/src/add-ons/kernel/file_systems/nfs4/FileInfo.cpp b/src/add-ons/kernel/file_systems/nfs4/FileInfo.cpp index b33eaa42c4..ec4b073e1b 100644 --- a/src/add-ons/kernel/file_systems/nfs4/FileInfo.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/FileInfo.cpp @@ -18,6 +18,8 @@ status_t FileInfo::ParsePath(RequestBuilder& req, uint32& count, const char* _path) { + ASSERT(_path != NULL); + char* path = strdup(_path); if (path == NULL) return B_NO_MEMORY; @@ -49,6 +51,8 @@ FileInfo::ParsePath(RequestBuilder& req, uint32& count, const char* _path) status_t FileInfo::CreateName(const char* dirPath, const char* name) { + ASSERT(name != NULL); + free(const_cast(fName)); fName = strdup(name); if (fName == NULL) @@ -81,6 +85,8 @@ FileInfo::CreateName(const char* dirPath, const char* name) status_t FileInfo::UpdateFileHandles(FileSystem* fs) { + ASSERT(fs != NULL); + Request request(fs->Server(), fs); RequestBuilder& req = request.Builder(); diff --git a/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp b/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp index 860c891e6f..66bb163f33 100644 --- a/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp @@ -60,6 +60,9 @@ FileSystem::~FileSystem() static const char* GetPath(const char* root, const char* path) { + ASSERT(root != NULL); + ASSERT(path != NULL); + int slash = 0; int i; for (i = 0; path[i] != '\0'; i++) { @@ -78,9 +81,13 @@ GetPath(const char* root, const char* path) status_t -FileSystem::Mount(FileSystem** pfs, RPC::Server* serv, const char* fsPath, +FileSystem::Mount(FileSystem** _fs, RPC::Server* serv, const char* fsPath, dev_t id, const MountConfiguration& configuration) { + ASSERT(_fs != NULL); + ASSERT(serv != NULL); + ASSERT(fsPath != NULL); + FileSystem* fs = new(std::nothrow) FileSystem(configuration); if (fs == NULL) return B_NO_MEMORY; @@ -187,7 +194,7 @@ FileSystem::Mount(FileSystem** pfs, RPC::Server* serv, const char* fsPath, fs->fRoot = reinterpret_cast(inode); fs->NFSServer()->AddFileSystem(fs); - *pfs = fs; + *_fs = fs; fsDeleter.Detach(); return B_OK; @@ -197,6 +204,8 @@ FileSystem::Mount(FileSystem** pfs, RPC::Server* serv, const char* fsPath, status_t FileSystem::GetInode(ino_t id, Inode** _inode) { + ASSERT(_inode != NULL); + FileInfo fi; status_t result = fInoIdMap.GetFileInfo(&fi, id); if (result == B_ENTRY_NOT_FOUND) @@ -218,6 +227,8 @@ FileSystem::GetInode(ino_t id, Inode** _inode) status_t FileSystem::Migrate(const RPC::Server* serv) { + ASSERT(serv != NULL); + MutexLocker _(fOpenLock); if (serv != fServer) return B_OK; @@ -295,6 +306,8 @@ FileSystem::OpenFilesUnlock() void FileSystem::AddOpenFile(OpenState* state) { + ASSERT(state != NULL); + MutexLocker _(fOpenLock); fOpenFiles.InsertBefore(fOpenFiles.Head(), state); @@ -306,6 +319,8 @@ FileSystem::AddOpenFile(OpenState* state) void FileSystem::RemoveOpenFile(OpenState* state) { + ASSERT(state != NULL); + MutexLocker _(fOpenLock); fOpenFiles.Remove(state); @@ -332,6 +347,8 @@ FileSystem::DelegationsUnlock() void FileSystem::AddDelegation(Delegation* delegation) { + ASSERT(delegation != NULL); + MutexLocker _(fDelegationLock); fDelegationList.InsertBefore(fDelegationList.Head(), delegation); @@ -344,6 +361,8 @@ FileSystem::AddDelegation(Delegation* delegation) void FileSystem::RemoveDelegation(Delegation* delegation) { + ASSERT(delegation != NULL); + MutexLocker _(fDelegationLock); fDelegationList.Remove(delegation); diff --git a/src/add-ons/kernel/file_systems/nfs4/FileSystem.h b/src/add-ons/kernel/file_systems/nfs4/FileSystem.h index e7884fed41..2937066e41 100644 --- a/src/add-ons/kernel/file_systems/nfs4/FileSystem.h +++ b/src/add-ons/kernel/file_systems/nfs4/FileSystem.h @@ -153,6 +153,7 @@ FileSystem::ExpireType() const inline RPC::Server* FileSystem::Server() { + ASSERT(fServer != NULL); return fServer; } @@ -160,6 +161,7 @@ FileSystem::Server() inline NFS4Server* FileSystem::NFSServer() { + ASSERT(fServer->PrivateData() != NULL); return reinterpret_cast(fServer->PrivateData()); } @@ -167,6 +169,7 @@ FileSystem::NFSServer() inline const char* FileSystem::Path() const { + ASSERT(fPath != NULL); return fPath; } diff --git a/src/add-ons/kernel/file_systems/nfs4/IdMap.cpp b/src/add-ons/kernel/file_systems/nfs4/IdMap.cpp index 2eef09dcfa..146b07767c 100644 --- a/src/add-ons/kernel/file_systems/nfs4/IdMap.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/IdMap.cpp @@ -38,6 +38,7 @@ IdMap::~IdMap() uid_t IdMap::GetUserId(const char* owner) { + ASSERT(owner != NULL); return _GetValue(owner, MsgNameToUID); } @@ -45,6 +46,7 @@ IdMap::GetUserId(const char* owner) gid_t IdMap::GetGroupId(const char* ownerGroup) { + ASSERT(ownerGroup != NULL); return _GetValue(ownerGroup, MsgNameToGID); } @@ -67,6 +69,8 @@ template T IdMap::_GetValue(const char* buffer, int32 code) { + ASSERT(buffer != NULL); + MutexLocker _(fLock); do { status_t result = write_port(fRequestPort, MsgNameToUID, buffer, diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index 2a7705403c..ab9cbf4cb3 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -41,6 +41,9 @@ Inode::Inode() status_t Inode::CreateInode(FileSystem* fs, const FileInfo& fi, Inode** _inode) { + ASSERT(fs != NULL); + ASSERT(_inode != NULL); + Inode* inode = NULL; if (fs->Root() == NULL) inode = new(std::nothrow) RootInode; @@ -175,6 +178,9 @@ Inode::RevalidateFileCache() status_t Inode::LookUp(const char* name, ino_t* id) { + ASSERT(name != NULL); + ASSERT(id != NULL); + if (fType != NF4DIR) return B_NOT_A_DIRECTORY; @@ -218,6 +224,9 @@ Inode::LookUp(const char* name, ino_t* id) status_t Inode::Link(Inode* dir, const char* name) { + ASSERT(dir != NULL); + ASSERT(name != NULL); + ChangeInfo changeInfo; status_t result = NFS4Inode::Link(dir, name, &changeInfo); if (result != B_OK) @@ -253,6 +262,8 @@ Inode::Link(Inode* dir, const char* name) status_t Inode::Remove(const char* name, FileType type, ino_t* id) { + ASSERT(name != NULL); + MemoryDeleter nameDeleter; if (type == NF4NAMEDATTR) { status_t result = LoadAttrDirHandle(); @@ -303,6 +314,11 @@ status_t Inode::Rename(Inode* from, Inode* to, const char* fromName, const char* toName, bool attribute, ino_t* id) { + ASSERT(from != NULL); + ASSERT(fromName != NULL); + ASSERT(to != NULL); + ASSERT(toName != NULL); + if (from->fFileSystem != to->fFileSystem) return B_DONT_DO_THAT; @@ -386,6 +402,9 @@ Inode::CreateLink(const char* name, const char* path, int mode) status_t Inode::CreateObject(const char* name, const char* path, int mode, FileType type) { + ASSERT(name != NULL); + ASSERT(type != NF4LNK || path != NULL); + ChangeInfo changeInfo; uint64 fileID; FileHandle handle; @@ -455,6 +474,8 @@ Inode::Access(int mode) status_t Inode::Stat(struct stat* st, OpenAttrCookie* attr) { + ASSERT(st != NULL); + if (attr != NULL) return GetStat(st, attr); @@ -479,6 +500,8 @@ Inode::Stat(struct stat* st, OpenAttrCookie* attr) status_t Inode::GetStat(struct stat* st, OpenAttrCookie* attr) { + ASSERT(st != NULL); + AttrValue* values; uint32 count; status_t result = NFS4Inode::GetStat(&values, &count, attr); @@ -566,6 +589,8 @@ Inode::GetStat(struct stat* st, OpenAttrCookie* attr) status_t Inode::WriteStat(const struct stat* st, uint32 mask, OpenAttrCookie* cookie) { + ASSERT(st != NULL); + status_t result; AttrValue attr[6]; uint32 i = 0; @@ -616,6 +641,7 @@ Inode::WriteStat(const struct stat* st, uint32 mask, OpenAttrCookie* cookie) if (cookie == NULL) { MutexLocker stateLocker(fStateLock); + ASSERT(fOpenState != NULL); result = NFS4Inode::WriteStat(fOpenState, attr, i); stateLocker.Unlock(); @@ -657,6 +683,9 @@ Inode::CheckLockType(short ltype, uint32 mode) status_t Inode::TestLock(OpenFileCookie* cookie, struct flock* lock) { + ASSERT(cookie != NULL); + ASSERT(lock != NULL); + if (lock->l_type == F_UNLCK) return B_OK; @@ -691,6 +720,9 @@ status_t Inode::AcquireLock(OpenFileCookie* cookie, const struct flock* lock, bool wait) { + ASSERT(cookie != NULL); + ASSERT(lock != NULL); + OpenState* state = cookie->fOpenState; status_t result = CheckLockType(lock->l_type, cookie->fMode); @@ -732,6 +764,9 @@ Inode::AcquireLock(OpenFileCookie* cookie, const struct flock* lock, status_t Inode::ReleaseLock(OpenFileCookie* cookie, const struct flock* lock) { + ASSERT(cookie != NULL); + ASSERT(lock != NULL); + SyncAndCommit(); LockInfo* prev = NULL; @@ -782,6 +817,8 @@ Inode::ReleaseLock(OpenFileCookie* cookie, const struct flock* lock) status_t Inode::ReleaseAllLocks(OpenFileCookie* cookie) { + ASSERT(cookie != NULL); + SyncAndCommit(); OpenState* state = cookie->fOpenState; @@ -816,6 +853,8 @@ status_t Inode::ChildAdded(const char* name, uint64 fileID, const FileHandle& fileHandle) { + ASSERT(name != NULL); + fFileSystem->Root()->MakeInfoInvalid(); FileInfo fi; @@ -840,6 +879,8 @@ Inode::Name() const void Inode::SetDelegation(Delegation* delegation) { + ASSERT(delegation != NULL); + WriteLocker _(fDelegationLock); fMetaCache.InvalidateStat(); diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h b/src/add-ons/kernel/file_systems/nfs4/Inode.h index 1201d2857e..190154f713 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -187,6 +187,7 @@ Inode::Type() const inline FileSystem* Inode::GetFileSystem() const { + ASSERT(fFileSystem != NULL); return fFileSystem; } @@ -201,6 +202,7 @@ Inode::FileCache() inline void Inode::SetOpenState(OpenState* state) { + ASSERT(state != NULL); MutexLocker _(fStateLock); fOpenState = state; } diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp b/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp index 7e374c3448..909696cac7 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp @@ -27,6 +27,8 @@ Inode::CreateDir(const char* name, int mode) status_t Inode::OpenDir(OpenDirCookie* cookie) { + ASSERT(cookie != NULL); + if (fType != NF4DIR) return B_NOT_A_DIRECTORY; @@ -48,6 +50,8 @@ Inode::OpenDir(OpenDirCookie* cookie) status_t Inode::OpenAttrDir(OpenDirCookie* cookie) { + ASSERT(cookie != NULL); + cookie->fFileSystem = fFileSystem; cookie->fSpecial = 0; cookie->fSnapshot = NULL; @@ -116,6 +120,9 @@ status_t Inode::FillDirEntry(struct dirent* de, ino_t id, const char* name, uint32 pos, uint32 size) { + ASSERT(de != NULL); + ASSERT(name != NULL); + uint32 nameSize = strlen(name); const uint32 entSize = sizeof(struct dirent); @@ -137,6 +144,8 @@ Inode::FillDirEntry(struct dirent* de, ino_t id, const char* name, uint32 pos, status_t Inode::ReadDirUp(struct dirent* de, uint32 pos, uint32 size) { + ASSERT(de != NULL); + do { RPC::Server* serv = fFileSystem->Server(); Request request(serv, fFileSystem); @@ -189,6 +198,8 @@ Inode::ReadDirUp(struct dirent* de, uint32 pos, uint32 size) static char* FileToAttrName(const char* path) { + ASSERT(path != NULL); + char* name = strdup(path); if (name == NULL) return NULL; @@ -214,6 +225,8 @@ status_t Inode::GetDirSnapshot(DirectoryCacheSnapshot** _snapshot, OpenDirCookie* cookie, uint64* _change, bool attribute) { + ASSERT(_snapshot != NULL); + DirectoryCacheSnapshot* snapshot = new DirectoryCacheSnapshot; if (snapshot == NULL) return B_NO_MEMORY; @@ -292,6 +305,10 @@ status_t Inode::ReadDir(void* _buffer, uint32 size, uint32* _count, OpenDirCookie* cookie) { + ASSERT(_buffer != NULL); + ASSERT(_count != NULL); + ASSERT(cookie != NULL); + if (cookie->fEOF) { *_count = 0; return B_OK; diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeIdMap.h b/src/add-ons/kernel/file_systems/nfs4/InodeIdMap.h index ae85c32594..a6bbd48704 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeIdMap.h +++ b/src/add-ons/kernel/file_systems/nfs4/InodeIdMap.h @@ -69,6 +69,8 @@ InodeIdMap::RemoveEntry(ino_t id) inline status_t InodeIdMap::GetFileInfo(FileInfo* fi, ino_t id) { + ASSERT(fi != NULL); + MutexLocker _(fLock); AVLTreeMap::Iterator it = fMap.Find(id); if (!it.HasCurrent()) diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp index 811013fb7c..d5fa76d8d4 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp @@ -23,6 +23,10 @@ status_t Inode::CreateState(const char* name, int mode, int perms, OpenState* state, OpenDelegationData* delegationData) { + ASSERT(name != NULL); + ASSERT(state != NULL); + ASSERT(delegationData != NULL); + uint64 fileID; FileHandle handle; ChangeInfo changeInfo; @@ -64,6 +68,10 @@ status_t Inode::Create(const char* name, int mode, int perms, OpenFileCookie* cookie, OpenDelegationData* data, ino_t* id) { + ASSERT(name != NULL); + ASSERT(cookie != NULL); + ASSERT(data != NULL); + cookie->fMode = mode; cookie->fLocks = NULL; @@ -94,6 +102,8 @@ Inode::Create(const char* name, int mode, int perms, OpenFileCookie* cookie, status_t Inode::Open(int mode, OpenFileCookie* cookie) { + ASSERT(cookie != NULL); + MutexLocker locker(fStateLock); OpenDelegationData data; @@ -178,6 +188,8 @@ Inode::Open(int mode, OpenFileCookie* cookie) status_t Inode::Close(OpenFileCookie* cookie) { + ASSERT(cookie != NULL); + SyncAndCommit(); MutexLocker _(fStateLock); @@ -190,6 +202,8 @@ Inode::Close(OpenFileCookie* cookie) char* Inode::AttrToFileName(const char* path) { + ASSERT(path != NULL); + char* name = strdup(path); if (name == NULL) return NULL; @@ -215,6 +229,9 @@ status_t Inode::OpenAttr(const char* _name, int mode, OpenAttrCookie* cookie, bool create, int32 type) { + ASSERT(_name != NULL); + ASSERT(cookie != NULL); + (void)type; status_t result = LoadAttrDirHandle(); @@ -272,6 +289,8 @@ Inode::OpenAttr(const char* _name, int mode, OpenAttrCookie* cookie, status_t Inode::CloseAttr(OpenAttrCookie* cookie) { + ASSERT(cookie != NULL); + if (cookie->fOpenState->fDelegation != NULL) { cookie->fOpenState->fDelegation->GiveUp(); fFileSystem->RemoveDelegation(cookie->fOpenState->fDelegation); @@ -287,6 +306,11 @@ status_t Inode::ReadDirect(OpenStateCookie* cookie, off_t pos, void* buffer, size_t* _length, bool* eof) { + ASSERT(cookie != NULL || fOpenState != NULL); + ASSERT(buffer != NULL); + ASSERT(_length != NULL); + ASSERT(eof != NULL); + *eof = false; uint32 size = 0; @@ -318,6 +342,10 @@ Inode::ReadDirect(OpenStateCookie* cookie, off_t pos, void* buffer, status_t Inode::Read(OpenFileCookie* cookie, off_t pos, void* buffer, size_t* _length) { + ASSERT(cookie != NULL); + ASSERT(buffer != NULL); + ASSERT(_length != NULL); + bool eof = false; if ((cookie->fMode & O_NOCACHE) != 0) return ReadDirect(cookie, pos, buffer, _length, &eof); @@ -329,6 +357,10 @@ status_t Inode::WriteDirect(OpenStateCookie* cookie, off_t pos, const void* _buffer, size_t* _length) { + ASSERT(cookie != NULL || fOpenState != NULL); + ASSERT(_buffer != NULL); + ASSERT(_length != NULL); + uint32 size = 0; const char* buffer = reinterpret_cast(_buffer); @@ -372,6 +404,10 @@ status_t Inode::Write(OpenFileCookie* cookie, off_t pos, const void* _buffer, size_t* _length) { + ASSERT(cookie != NULL); + ASSERT(_buffer != NULL); + ASSERT(_length != NULL); + struct stat st; status_t result = Stat(&st); if (result != B_OK) diff --git a/src/add-ons/kernel/file_systems/nfs4/MetadataCache.cpp b/src/add-ons/kernel/file_systems/nfs4/MetadataCache.cpp index 38795b4402..570f6da44b 100644 --- a/src/add-ons/kernel/file_systems/nfs4/MetadataCache.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/MetadataCache.cpp @@ -21,6 +21,7 @@ MetadataCache::MetadataCache(Inode* inode) fInode(inode), fInited(false) { + ASSERT(inode != NULL); mutex_init(&fLock, NULL); } @@ -34,6 +35,8 @@ MetadataCache::~MetadataCache() status_t MetadataCache::GetStat(struct stat* st) { + ASSERT(st != NULL); + MutexLocker _(fLock); if (fForceValid || fExpire > time(NULL)) { // Do not touch other members of struct stat @@ -79,6 +82,8 @@ MetadataCache::GrowFile(size_t newSize) status_t MetadataCache::GetAccess(uid_t uid, uint32* allowed) { + ASSERT(allowed != NULL); + MutexLocker _(fLock); AVLTreeMap::Iterator it = fAccessCache.Find(uid); if (!it.HasCurrent()) @@ -141,6 +146,9 @@ void MetadataCache::NotifyChanges(const struct stat* oldStat, const struct stat* newStat) { + ASSERT(oldStat != NULL); + ASSERT(newStat != NULL); + uint32 flags = 0; if (oldStat->st_size != newStat->st_size) flags |= B_STAT_SIZE; diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp index 73d176bc6f..9c374c931d 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp @@ -16,6 +16,8 @@ status_t NFS4Inode::GetChangeInfo(uint64* change, bool attrDir) { + ASSERT(change != NULL); + do { RPC::Server* serv = fFileSystem->Server(); Request request(serv, fFileSystem); @@ -84,6 +86,8 @@ NFS4Inode::CommitWrites() status_t NFS4Inode::Access(uint32* allowed) { + ASSERT(allowed != NULL); + do { RPC::Server* serv = fFileSystem->Server(); Request request(serv, fFileSystem); @@ -112,6 +116,11 @@ status_t NFS4Inode::LookUp(const char* name, uint64* change, uint64* fileID, FileHandle* handle, bool parent) { + ASSERT(name != NULL); + ASSERT(change != NULL); + ASSERT(fileID != NULL); + ASSERT(handle != NULL); + do { RPC::Server* serv = fFileSystem->Server(); Request request(serv, fFileSystem); @@ -197,6 +206,10 @@ NFS4Inode::LookUp(const char* name, uint64* change, uint64* fileID, status_t NFS4Inode::Link(Inode* dir, const char* name, ChangeInfo* changeInfo) { + ASSERT(dir != NULL); + ASSERT(name != NULL); + ASSERT(changeInfo != NULL); + do { RPC::Server* serv = fFileSystem->Server(); Request request(serv, fFileSystem); @@ -229,6 +242,9 @@ NFS4Inode::Link(Inode* dir, const char* name, ChangeInfo* changeInfo) status_t NFS4Inode::ReadLink(void* buffer, size_t* length) { + ASSERT(buffer != NULL); + ASSERT(length != NULL); + do { RPC::Server* serv = fFileSystem->Server(); Request request(serv, fFileSystem); @@ -260,6 +276,9 @@ NFS4Inode::ReadLink(void* buffer, size_t* length) status_t NFS4Inode::GetStat(AttrValue** values, uint32* count, OpenAttrCookie* cookie) { + ASSERT(values != NULL); + ASSERT(count != NULL); + do { RPC::Server* serv = fFileSystem->Server(); Request request(serv, fFileSystem); @@ -295,6 +314,8 @@ NFS4Inode::GetStat(AttrValue** values, uint32* count, OpenAttrCookie* cookie) status_t NFS4Inode::WriteStat(OpenState* state, AttrValue* attrs, uint32 attrCount) { + ASSERT(attrs != NULL); + do { RPC::Server* serv = fFileSystem->Server(); Request request(serv, fFileSystem); @@ -333,6 +354,13 @@ NFS4Inode::RenameNode(Inode* from, Inode* to, const char* fromName, const char* toName, ChangeInfo* fromChange, ChangeInfo* toChange, uint64* fileID, bool attribute) { + ASSERT(from != NULL); + ASSERT(to != NULL); + ASSERT(fromName != NULL); + ASSERT(toName != NULL); + ASSERT(fromChange != NULL); + ASSERT(toChange != NULL); + do { RPC::Server* serv = from->fFileSystem->Server(); Request request(serv, from->fFileSystem); @@ -419,6 +447,12 @@ NFS4Inode::CreateFile(const char* name, int mode, int perms, OpenState* state, ChangeInfo* changeInfo, uint64* fileID, FileHandle* handle, OpenDelegationData* delegation) { + ASSERT(name != NULL); + ASSERT(state != NULL); + ASSERT(changeInfo != NULL); + ASSERT(handle != NULL); + ASSERT(delegation != NULL); + bool confirm; status_t result; @@ -511,6 +545,9 @@ NFS4Inode::CreateFile(const char* name, int mode, int perms, OpenState* state, status_t NFS4Inode::OpenFile(OpenState* state, int mode, OpenDelegationData* delegation) { + ASSERT(state != NULL); + ASSERT(delegation != NULL); + bool confirm; status_t result; uint32 sequence = fFileSystem->OpenOwnerSequenceLock(); @@ -612,6 +649,10 @@ status_t NFS4Inode::OpenAttr(OpenState* state, const char* name, int mode, OpenDelegationData* delegation, bool create) { + ASSERT(name != NULL); + ASSERT(state != NULL); + ASSERT(delegation != NULL); + bool confirm; status_t result; uint32 sequence = fFileSystem->OpenOwnerSequenceLock(); @@ -669,6 +710,11 @@ status_t NFS4Inode::ReadFile(OpenStateCookie* cookie, OpenState* state, uint64 position, uint32* length, void* buffer, bool* eof) { + ASSERT(state != NULL); + ASSERT(length != NULL); + ASSERT(buffer != NULL); + ASSERT(eof != NULL); + do { RPC::Server* serv = fFileSystem->Server(); Request request(serv, fFileSystem); @@ -700,6 +746,9 @@ status_t NFS4Inode::WriteFile(OpenStateCookie* cookie, OpenState* state, uint64 position, uint32* length, const void* buffer, bool commit) { + ASSERT(state != NULL); + ASSERT(length != NULL); + ASSERT(buffer != NULL); do { RPC::Server* serv = fFileSystem->Server(); @@ -736,6 +785,10 @@ NFS4Inode::CreateObject(const char* name, const char* path, int mode, FileType type, ChangeInfo* changeInfo, uint64* fileID, FileHandle* handle, bool parent) { + ASSERT(name != NULL); + ASSERT(changeInfo != NULL); + ASSERT(handle != NULL); + do { RPC::Server* serv = fFileSystem->Server(); Request request(serv, fFileSystem); @@ -814,6 +867,9 @@ status_t NFS4Inode::RemoveObject(const char* name, FileType type, ChangeInfo* changeInfo, uint64* fileID) { + ASSERT(name != NULL); + ASSERT(changeInfo != NULL); + do { RPC::Server* serv = fFileSystem->Server(); Request request(serv, fFileSystem); @@ -890,6 +946,10 @@ NFS4Inode::ReadDirOnce(DirEntry** dirents, uint32* count, OpenDirCookie* cookie, bool* eof, uint64* change, uint64* dirCookie, uint64* dirCookieVerf, bool attribute) { + ASSERT(dirents != NULL); + ASSERT(count != NULL); + ASSERT(eof != NULL); + do { RPC::Server* serv = fFileSystem->Server(); Request request(serv, fFileSystem); @@ -960,6 +1020,8 @@ NFS4Inode::ReadDirOnce(DirEntry** dirents, uint32* count, OpenDirCookie* cookie, status_t NFS4Inode::OpenAttrDir(FileHandle* handle) { + ASSERT(handle != NULL); + do { RPC::Server* serv = fFileSystem->Server(); Request request(serv, fFileSystem); @@ -992,6 +1054,11 @@ status_t NFS4Inode::TestLock(OpenFileCookie* cookie, LockType* type, uint64* position, uint64* length, bool& conflict) { + ASSERT(cookie != NULL); + ASSERT(type != NULL); + ASSERT(position != NULL); + ASSERT(length != NULL); + do { RPC::Server* serv = fFileSystem->Server(); Request request(serv, fFileSystem); @@ -1026,6 +1093,9 @@ NFS4Inode::TestLock(OpenFileCookie* cookie, LockType* type, uint64* position, status_t NFS4Inode::AcquireLock(OpenFileCookie* cookie, LockInfo* lockInfo, bool wait) { + ASSERT(cookie != NULL); + ASSERT(lockInfo != NULL); + uint32 sequence = fFileSystem->OpenOwnerSequenceLock(); do { MutexLocker ownerLocker(lockInfo->fOwner->fLock); @@ -1073,6 +1143,9 @@ NFS4Inode::AcquireLock(OpenFileCookie* cookie, LockInfo* lockInfo, bool wait) status_t NFS4Inode::ReleaseLock(OpenFileCookie* cookie, LockInfo* lockInfo) { + ASSERT(cookie != NULL); + ASSERT(lockInfo != NULL); + do { MutexLocker ownerLocker(lockInfo->fOwner->fLock); diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp index 918c44f473..c4949a4511 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp @@ -143,6 +143,9 @@ status_t NFS4Object::ConfirmOpen(const FileHandle& fh, OpenState* state, uint32* sequence) { + ASSERT(state != NULL); + ASSERT(sequence != NULL); + do { RPC::Server* serv = fFileSystem->Server(); Request request(serv, fFileSystem); diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp index c7f5ee285c..1de3bcf463 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp @@ -24,6 +24,8 @@ NFS4Server::NFS4Server(RPC::Server* serv) fFileSystems(NULL), fServer(serv) { + ASSERT(serv != NULL); + mutex_init(&fClientIdLock, NULL); mutex_init(&fFSLock, NULL); mutex_init(&fThreadStartLock, NULL); @@ -78,6 +80,8 @@ NFS4Server::ServerRebooted(uint64 clientId) void NFS4Server::AddFileSystem(FileSystem* fs) { + ASSERT(fs != NULL); + MutexLocker _(fFSLock); fs->fPrev = NULL; fs->fNext = fFileSystems; @@ -93,6 +97,8 @@ NFS4Server::AddFileSystem(FileSystem* fs) void NFS4Server::RemoveFileSystem(FileSystem* fs) { + ASSERT(fs != NULL); + MutexLocker _(fFSLock); if (fs == fFileSystems) fFileSystems = fs->fNext; @@ -270,6 +276,7 @@ NFS4Server::_Renewal() status_t NFS4Server::_RenewalThreadStart(void* ptr) { + ASSERT(ptr != NULL); NFS4Server* server = reinterpret_cast(ptr); return server->_Renewal(); } @@ -279,6 +286,9 @@ status_t NFS4Server::ProcessCallback(RPC::CallbackRequest* request, Connection* connection) { + ASSERT(request != NULL); + ASSERT(connection != NULL); + RequestInterpreter req(request); ReplyBuilder reply(request->XID()); @@ -311,6 +321,9 @@ NFS4Server::ProcessCallback(RPC::CallbackRequest* request, status_t NFS4Server::CallbackRecall(RequestInterpreter* request, ReplyBuilder* reply) { + ASSERT(request != NULL); + ASSERT(reply != NULL); + uint32 stateID[3]; uint32 stateSeq; bool truncate; @@ -352,6 +365,9 @@ NFS4Server::CallbackRecall(RequestInterpreter* request, ReplyBuilder* reply) status_t NFS4Server::CallbackGetAttr(RequestInterpreter* request, ReplyBuilder* reply) { + ASSERT(request != NULL); + ASSERT(reply != NULL); + FileHandle handle; int mask; diff --git a/src/add-ons/kernel/file_systems/nfs4/OpenState.cpp b/src/add-ons/kernel/file_systems/nfs4/OpenState.cpp index c02ffb0d74..f83d656fab 100644 --- a/src/add-ons/kernel/file_systems/nfs4/OpenState.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/OpenState.cpp @@ -112,6 +112,8 @@ OpenState::DeleteLock(LockInfo* lock) status_t OpenState::_ReleaseLockOwner(LockOwner* owner) { + ASSERT(owner != NULL); + do { RPC::Server* server = fFileSystem->Server(); Request request(server, fFileSystem); diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCCall.cpp b/src/add-ons/kernel/file_systems/nfs4/RPCCall.cpp index fcc3124803..d0c009945a 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RPCCall.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RPCCall.cpp @@ -9,6 +9,7 @@ #include "RPCCall.h" +#include #include #include "RPCDefs.h" @@ -25,6 +26,9 @@ Call::Call() Call* Call::Create(uint32 proc, const Auth* creds, const Auth* ver) { + ASSERT(creds != NULL); + ASSERT(ver != NULL); + Call* call = new(std::nothrow) Call; if (call == NULL) return NULL; diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCCallback.cpp b/src/add-ons/kernel/file_systems/nfs4/RPCCallback.cpp index ddf5b63b01..baf6246759 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RPCCallback.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RPCCallback.cpp @@ -26,6 +26,8 @@ Callback::Callback(Server* server) status_t Callback::EnqueueRequest(CallbackRequest* request, Connection* connection) { + ASSERT(request != NULL); + ASSERT(connection != NULL); return fServer->PrivateData()->ProcessCallback(request, connection); } diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCCallbackRequest.cpp b/src/add-ons/kernel/file_systems/nfs4/RPCCallbackRequest.cpp index 7ed177326e..54b9ef7b6f 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RPCCallbackRequest.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RPCCallbackRequest.cpp @@ -11,6 +11,8 @@ #include +#include + #include "NFS4Defs.h" #include "RPCDefs.h" @@ -25,6 +27,8 @@ CallbackRequest::CallbackRequest(void* buffer, int size) fStream(buffer, size), fBuffer(buffer) { + ASSERT(buffer != NULL); + fXID = fStream.GetUInt(); if (fStream.GetUInt() != CALL) diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCCallbackServer.cpp b/src/add-ons/kernel/file_systems/nfs4/RPCCallbackServer.cpp index 4039c08496..f02a53c1bf 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RPCCallbackServer.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RPCCallbackServer.cpp @@ -50,6 +50,8 @@ CallbackServer::~CallbackServer() status_t CallbackServer::RegisterCallback(Callback* callback) { + ASSERT(callback != NULL); + status_t result = StartServer(); if (result != B_OK) return result; @@ -88,6 +90,8 @@ CallbackServer::RegisterCallback(Callback* callback) status_t CallbackServer::UnregisterCallback(Callback* callback) { + ASSERT(callback != NULL); + int32 id = callback->ID(); WriteLocker _(fArrayLock); @@ -161,6 +165,8 @@ CallbackServer::StopServer() status_t CallbackServer::NewConnection(Connection* connection) { + ASSERT(connection != NULL); + ConnectionEntry* entry = new ConnectionEntry; entry->fConnection = connection; entry->fPrev = NULL; @@ -205,6 +211,8 @@ CallbackServer::NewConnection(Connection* connection) status_t CallbackServer::ReleaseConnection(ConnectionEntry* entry) { + ASSERT(entry != NULL); + MutexLocker _(fConnectionLock); if (entry->fNext != NULL) entry->fNext->fPrev = entry->fPrev; @@ -222,6 +230,8 @@ CallbackServer::ReleaseConnection(ConnectionEntry* entry) status_t CallbackServer::ConnectionThreadLauncher(void* object) { + ASSERT(object != NULL); + void** objects = reinterpret_cast(object); CallbackServer* server = reinterpret_cast(objects[0]); ConnectionEntry* entry = reinterpret_cast(objects[1]); @@ -234,6 +244,8 @@ CallbackServer::ConnectionThreadLauncher(void* object) status_t CallbackServer::ConnectionThread(ConnectionEntry* entry) { + ASSERT(entry != NULL); + Connection* connection = entry->fConnection; CallbackReply* reply; @@ -287,6 +299,8 @@ CallbackServer::ConnectionThread(ConnectionEntry* entry) status_t CallbackServer::ListenerThreadLauncher(void* object) { + ASSERT(object != NULL); + CallbackServer* server = reinterpret_cast(object); return server->ListenerThread(); } diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCReply.cpp b/src/add-ons/kernel/file_systems/nfs4/RPCReply.cpp index 4166d4e24c..bca2eaa5bf 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RPCReply.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RPCReply.cpp @@ -9,6 +9,7 @@ #include "RPCReply.h" +#include #include #include "RPCDefs.h" @@ -23,6 +24,8 @@ Reply::Reply(void* buffer, int size) fStream(buffer, size), fBuffer(buffer) { + ASSERT(buffer != NULL); + fXID = fStream.GetUInt(); if (fStream.GetInt() != REPLY) { fError = B_BAD_VALUE; diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp b/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp index 4095d4111a..de2faf589a 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp @@ -38,6 +38,8 @@ RequestManager::~RequestManager() void RequestManager::AddRequest(Request* request) { + ASSERT(request != NULL); + MutexLocker _(fLock); if (fQueueTail != NULL) fQueueTail->fNext = request; @@ -81,6 +83,9 @@ Server::Server(Connection* connection, PeerAddress* address) fCallback(NULL), fXID(rand() << 1) { + ASSERT(connection != NULL); + ASSERT(address != NULL); + mutex_init(&fCallbackLock, NULL); _StartListening(); @@ -129,6 +134,9 @@ Server::_StartListening() status_t Server::SendCall(Call* call, Reply** reply) { + ASSERT(call != NULL); + ASSERT(reply != NULL); + Request* req; status_t result = SendCallAsync(call, reply, &req); if (result != B_OK) @@ -149,6 +157,10 @@ Server::SendCall(Call* call, Reply** reply) status_t Server::SendCallAsync(Call* call, Reply** reply, Request** request) { + ASSERT(call != NULL); + ASSERT(reply != NULL); + ASSERT(request != NULL); + if (fThreadError != B_OK) return fThreadError; @@ -175,6 +187,9 @@ Server::SendCallAsync(Call* call, Reply** reply, Request** request) status_t Server::ResendCallAsync(Call* call, Request* request) { + ASSERT(call != NULL); + ASSERT(request != NULL); + if (fThreadError != B_OK) { fRequests.FindRequest(request->fXID); delete request; @@ -196,6 +211,8 @@ Server::ResendCallAsync(Call* call, Request* request) status_t Server::WakeCall(Request* request) { + ASSERT(request != NULL); + Request* req = fRequests.FindRequest(request->fXID); if (req == NULL) return B_OK; @@ -281,6 +298,8 @@ Server::_Listener() status_t Server::_ListenerThreadStart(void* object) { + ASSERT(object != NULL); + Server* server = reinterpret_cast(object); return server->_Listener(); } @@ -304,6 +323,9 @@ status_t ServerManager::Acquire(Server** _server, const PeerAddress& address, ProgramData* (*createPrivateData)(Server*)) { + ASSERT(_server != NULL); + ASSERT(createPrivateData != NULL); + status_t result; MutexLocker locker(fLock); @@ -357,6 +379,8 @@ ServerManager::Acquire(Server** _server, const PeerAddress& address, void ServerManager::Release(Server* server) { + ASSERT(server != NULL); + MutexLocker _(fLock); ServerNode* node = _Find(server->ID()); if (node != NULL) { @@ -391,6 +415,8 @@ ServerManager::_Find(const PeerAddress& address) void ServerManager::_Delete(ServerNode* node) { + ASSERT(node != NULL); + bool found = false; ServerNode* previous = NULL; ServerNode* current = fRoot; @@ -452,6 +478,8 @@ ServerManager::_Delete(ServerNode* node) ServerNode* ServerManager::_Insert(ServerNode* node) { + ASSERT(node != NULL); + ServerNode* previous = NULL; ServerNode* current = fRoot; while (current != NULL) { diff --git a/src/add-ons/kernel/file_systems/nfs4/Request.h b/src/add-ons/kernel/file_systems/nfs4/Request.h index 2c0d014708..f740bb4619 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Request.h +++ b/src/add-ons/kernel/file_systems/nfs4/Request.h @@ -46,6 +46,7 @@ Request::Request(RPC::Server* server, FileSystem* fileSystem) fServer(server), fFileSystem(fileSystem) { + ASSERT(server != NULL); } diff --git a/src/add-ons/kernel/file_systems/nfs4/RootInode.cpp b/src/add-ons/kernel/file_systems/nfs4/RootInode.cpp index 65fbd73247..a215d6bb7b 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RootInode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RootInode.cpp @@ -35,6 +35,8 @@ RootInode::~RootInode() status_t RootInode::ReadInfo(struct fs_info* info) { + ASSERT(info != NULL); + status_t result = _UpdateInfo(); if (result != B_OK) return result; @@ -172,6 +174,8 @@ RootInode::ProbeMigration() status_t RootInode::GetLocations(AttrValue** attrv) { + ASSERT(attrv != NULL); + do { RPC::Server* server = fFileSystem->Server(); Request request(server, fFileSystem); @@ -209,6 +213,7 @@ RootInode::GetLocations(AttrValue** attrv) const char* RootInode::Name() const { + ASSERT(fName != NULL); return fName; } diff --git a/src/add-ons/kernel/file_systems/nfs4/RootInode.h b/src/add-ons/kernel/file_systems/nfs4/RootInode.h index 4810b7829d..8fff6adc1a 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RootInode.h +++ b/src/add-ons/kernel/file_systems/nfs4/RootInode.h @@ -63,6 +63,8 @@ RootInode::IOSize() inline void RootInode::SetName(const char* name) { + ASSERT(name != NULL); + free(const_cast(fName)); fName = strdup(name); } diff --git a/src/add-ons/kernel/file_systems/nfs4/WorkQueue.cpp b/src/add-ons/kernel/file_systems/nfs4/WorkQueue.cpp index 9a19120966..8806436351 100644 --- a/src/add-ons/kernel/file_systems/nfs4/WorkQueue.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/WorkQueue.cpp @@ -74,6 +74,8 @@ WorkQueue::EnqueueJob(JobType type, void* args) status_t WorkQueue::LaunchWorkingThread(void* object) { + ASSERT(object != NULL); + WorkQueue* queue = reinterpret_cast(object); return queue->WorkingThread(); } @@ -115,6 +117,7 @@ WorkQueue::DequeueJob() MutexLocker locker(fQueueLock); WorkQueueEntry* entry = fQueue.RemoveHead(); + ASSERT(entry != NULL); void* args = entry->fArguments; switch (entry->fType) { @@ -133,6 +136,7 @@ WorkQueue::DequeueJob() void WorkQueue::JobRecall(DelegationRecallArgs* args) { + ASSERT(args != NULL); args->fDelegation->GetInode()->RecallDelegation(args->fTruncate); } @@ -140,6 +144,8 @@ WorkQueue::JobRecall(DelegationRecallArgs* args) void WorkQueue::JobIO(IORequestArgs* args) { + ASSERT(args != NULL); + uint64 offset = io_request_offset(args->fRequest); uint64 length = io_request_length(args->fRequest); 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 636d3c5965..11ef428715 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -14,6 +14,7 @@ #include #include "Connection.h" +#include "Debug.h" #include "FileSystem.h" #include "IdMap.h" #include "Inode.h" From b70890b1386f973df95454ba605cc8ad5b79c55f Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Thu, 1 Nov 2012 01:03:20 +0100 Subject: [PATCH 212/252] nfs4: Add basic tracing of nfs4 module calls --- .../file_systems/nfs4/kernel_interface.cpp | 122 +++++++++++++++++- 1 file changed, 121 insertions(+), 1 deletion(-) 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 11ef428715..498d1e5f2c 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -14,7 +14,6 @@ #include #include "Connection.h" -#include "Debug.h" #include "FileSystem.h" #include "IdMap.h" #include "Inode.h" @@ -26,6 +25,22 @@ #include "RPCServer.h" #include "WorkQueue.h" +#define TRACE_NFS4 + +#ifdef TRACE_NFS4 +static mutex gTraceLock = MUTEX_INITIALIZER(NULL); + +#define TRACE(x...) \ + { \ + mutex_lock(&gTraceLock); \ + dprintf("%s(): ", __FUNCTION__); \ + dprintf(x); \ + dprintf("\n"); \ + mutex_unlock(&gTraceLock); \ + } +#else +#define TRACE(x...) (void)0 +#endif extern fs_volume_ops gNFSv4VolumeOps; extern fs_vnode_ops gNFSv4VnodeOps; @@ -123,6 +138,9 @@ static status_t nfs4_mount(fs_volume* volume, const char* device, uint32 flags, const char* args, ino_t* _rootVnodeID) { + TRACE("volume = %p, device = %s, flags = %lu, args = %s", volume, device, + flags, args); + status_t result; /* prepare idmapper server */ @@ -177,6 +195,8 @@ nfs4_mount(fs_volume* volume, const char* device, uint32 flags, *_rootVnodeID = inode->ID(); + TRACE("*_rootVnodeID = %llu", inode->ID()); + return B_OK; } @@ -185,6 +205,8 @@ static status_t nfs4_get_vnode(fs_volume* volume, ino_t id, fs_vnode* vnode, int* _type, uint32* _flags, bool reenter) { + TRACE("volume = %p, id = %llu", volume, id); + FileSystem* fs = reinterpret_cast(volume->private_volume); Inode* inode; status_t result = fs->GetInode(id, &inode); @@ -204,6 +226,7 @@ nfs4_get_vnode(fs_volume* volume, ino_t id, fs_vnode* vnode, int* _type, static status_t nfs4_unmount(fs_volume* volume) { + TRACE("volume = %p", volume); FileSystem* fs = reinterpret_cast(volume->private_volume); RPC::Server* server = fs->Server(); @@ -217,6 +240,8 @@ nfs4_unmount(fs_volume* volume) static status_t nfs4_read_fs_info(fs_volume* volume, struct fs_info* info) { + TRACE("volume = %p", volume); + FileSystem* fs = reinterpret_cast(volume->private_volume); RootInode* inode = reinterpret_cast(fs->Root()); return inode->ReadInfo(info); @@ -227,11 +252,16 @@ static status_t nfs4_lookup(fs_volume* volume, fs_vnode* dir, const char* name, ino_t* _id) { Inode* inode = reinterpret_cast(dir->private_node); + + TRACE("volume = %p, dir = %llu, name = %s", volume, inode->ID(), name); + status_t result = inode->LookUp(name, _id); if (result != B_OK) return result; void* ptr; + + TRACE("*_id = %llu", *_id); return get_vnode(volume, *_id, &ptr); } @@ -241,6 +271,9 @@ nfs4_get_vnode_name(fs_volume* volume, fs_vnode* vnode, char* buffer, size_t bufferSize) { Inode* inode = reinterpret_cast(vnode->private_node); + + TRACE("volume = %p, vnode = %llu", volume, inode->ID()); + strncpy(buffer, inode->Name(), bufferSize); return B_OK; } @@ -251,6 +284,9 @@ nfs4_put_vnode(fs_volume* volume, fs_vnode* vnode, bool reenter) { FileSystem* fs = reinterpret_cast(volume->private_volume); Inode* inode = reinterpret_cast(vnode->private_node); + + TRACE("volume = %p, vnode = %llu", volume, inode->ID()); + if (fs->Root() == inode) return B_OK; @@ -270,6 +306,9 @@ nfs4_remove_vnode(fs_volume* volume, fs_vnode* vnode, bool reenter) FileSystem* fs = reinterpret_cast(volume->private_volume); Inode* inode = reinterpret_cast(vnode->private_node); + + TRACE("volume = %p, vnode = %llu", volume, inode->ID()); + if (fs->Root() == inode) return B_OK; @@ -285,6 +324,11 @@ nfs4_read_pages(fs_volume* _volume, fs_vnode* vnode, void* _cookie, off_t pos, const iovec* vecs, size_t count, size_t* _numBytes) { Inode* inode = reinterpret_cast(vnode->private_node); + + TRACE("volume = %p, vnode = %llu, cookie = %p, pos = %llu, " \ + "count = %lu, numBytes = %lu", _volume, inode->ID(), _cookie, pos, + count, *_numBytes); + OpenFileCookie* cookie = reinterpret_cast(_cookie); status_t result; @@ -309,6 +353,8 @@ nfs4_read_pages(fs_volume* _volume, fs_vnode* vnode, void* _cookie, off_t pos, *_numBytes = totalRead; + TRACE("*numBytes = %lu", totalRead); + return B_OK; } @@ -318,6 +364,11 @@ nfs4_write_pages(fs_volume* _volume, fs_vnode* vnode, void* _cookie, off_t pos, const iovec* vecs, size_t count, size_t* _numBytes) { Inode* inode = reinterpret_cast(vnode->private_node); + + TRACE("volume = %p, vnode = %llu, cookie = %p, pos = %llu, " \ + "count = %lu, numBytes = %lu", _volume, inode->ID(), _cookie, pos, + count, *_numBytes); + OpenFileCookie* cookie = reinterpret_cast(_cookie); status_t result; @@ -350,6 +401,9 @@ nfs4_io(fs_volume* volume, fs_vnode* vnode, void* cookie, io_request* request) { Inode* inode = reinterpret_cast(vnode->private_node); + TRACE("volume = %p, vnode = %llu, cookie = %p", volume, inode->ID(), + cookie); + IORequestArgs* args = new(std::nothrow) IORequestArgs; if (args == NULL) { notify_io_request(request, B_NO_MEMORY); @@ -377,6 +431,9 @@ nfs4_get_file_map(fs_volume* volume, fs_vnode* vnode, off_t _offset, static status_t nfs4_set_flags(fs_volume* volume, fs_vnode* vnode, void* _cookie, int flags) { + TRACE("volume = %p, vnode = %llu, cookie = %p, flags = %d", volume, + reinterpret_cast(vnode->private_node)->ID(), _cookie, flags); + OpenFileCookie* cookie = reinterpret_cast(_cookie); cookie->fMode = (cookie->fMode & ~(O_APPEND | O_NONBLOCK)) | flags; return B_OK; @@ -387,6 +444,7 @@ static status_t nfs4_fsync(fs_volume* volume, fs_vnode* vnode) { Inode* inode = reinterpret_cast(vnode->private_node); + TRACE("volume = %p, vnode = %llu", volume, inode->ID()); return inode->SyncAndCommit(); } @@ -396,6 +454,7 @@ nfs4_read_symlink(fs_volume* volume, fs_vnode* link, char* buffer, size_t* _bufferSize) { Inode* inode = reinterpret_cast(link->private_node); + TRACE("volume = %p, link = %llu", volume, inode->ID()); return inode->ReadLink(buffer, _bufferSize); } @@ -405,6 +464,8 @@ nfs4_create_symlink(fs_volume* volume, fs_vnode* dir, const char* name, const char* path, int mode) { Inode* inode = reinterpret_cast(dir->private_node); + TRACE("volume = %p, dir = %llu, name = %s, path = %s, mode = %d", volume, + inode->ID(), name, path, mode); return inode->CreateLink(name, path, mode); } @@ -414,6 +475,8 @@ nfs4_link(fs_volume* volume, fs_vnode* dir, const char* name, fs_vnode* vnode) { Inode* inode = reinterpret_cast(vnode->private_node); Inode* dirInode = reinterpret_cast(dir->private_node); + TRACE("volume = %p, dir = %llu, name = %s, vnode = %llu", volume, + dirInode->ID(), name, inode->ID()); return inode->Link(dirInode, name); } @@ -423,6 +486,8 @@ nfs4_unlink(fs_volume* volume, fs_vnode* dir, const char* name) { Inode* inode = reinterpret_cast(dir->private_node); + TRACE("volume = %p, dir = %llu, name = %s", volume, inode->ID(), name); + ino_t id; status_t result = inode->Remove(name, NF4REG, &id); if (result != B_OK) @@ -439,6 +504,10 @@ nfs4_rename(fs_volume* volume, fs_vnode* fromDir, const char* fromName, Inode* fromInode = reinterpret_cast(fromDir->private_node); Inode* toInode = reinterpret_cast(toDir->private_node); + TRACE("volume = %p, fromDir = %llu, toDir = %llu, fromName = %s, " \ + "toName = %s", volume, fromInode->ID(), toInode->ID(), fromName, + toName); + ino_t id; status_t result = Inode::Rename(fromInode, toInode, fromName, toName, false, &id); @@ -460,6 +529,7 @@ static status_t nfs4_access(fs_volume* volume, fs_vnode* vnode, int mode) { Inode* inode = reinterpret_cast(vnode->private_node); + TRACE("volume = %p, vnode = %llu, mode = %d", volume, inode->ID(), mode); return inode->Access(mode); } @@ -468,6 +538,7 @@ static status_t nfs4_read_stat(fs_volume* volume, fs_vnode* vnode, struct stat* stat) { Inode* inode = reinterpret_cast(vnode->private_node); + TRACE("volume = %p, vnode = %llu", volume, inode->ID()); return inode->Stat(stat); } @@ -477,6 +548,8 @@ nfs4_write_stat(fs_volume* volume, fs_vnode* vnode, const struct stat* stat, uint32 statMask) { Inode* inode = reinterpret_cast(vnode->private_node); + TRACE("volume = %p, vnode = %llu, statMask = %lu", volume, inode->ID(), + statMask); return inode->WriteStat(stat, statMask); } @@ -492,6 +565,9 @@ nfs4_create(fs_volume* volume, fs_vnode* dir, const char* name, int openMode, Inode* inode = reinterpret_cast(dir->private_node); + TRACE("volume = %p, dir = %llu, name = %s, openMode = %d, perms = %d", + volume, inode->ID(), name, openMode, perms); + OpenDelegationData data; status_t result = inode->Create(name, openMode, perms, cookie, &data, _newVnodeID); @@ -530,6 +606,8 @@ nfs4_create(fs_volume* volume, fs_vnode* dir, const char* name, int openMode, } } + TRACE("*cookie = %p, *newVnodeID = %llu", *_cookie, *_newVnodeID); + return result; } @@ -539,6 +617,9 @@ nfs4_open(fs_volume* volume, fs_vnode* vnode, int openMode, void** _cookie) { Inode* inode = reinterpret_cast(vnode->private_node); + TRACE("volume = %p, vnode = %llu, openMode = %d", volume, inode->ID(), + openMode); + if (inode->Type() == S_IFDIR || inode->Type() == S_IFLNK) { *_cookie = NULL; return B_OK; @@ -553,6 +634,8 @@ nfs4_open(fs_volume* volume, fs_vnode* vnode, int openMode, void** _cookie) if (result != B_OK) delete cookie; + TRACE("*cookie = %p", *_cookie); + return result; } @@ -562,6 +645,9 @@ nfs4_close(fs_volume* volume, fs_vnode* vnode, void* _cookie) { Inode* inode = reinterpret_cast(vnode->private_node); + TRACE("volume = %p, vnode = %llu, cookie = %p", volume, inode->ID(), + _cookie); + if (inode->Type() == S_IFDIR || inode->Type() == S_IFLNK) return B_OK; @@ -575,6 +661,9 @@ nfs4_free_cookie(fs_volume* volume, fs_vnode* vnode, void* _cookie) { Inode* inode = reinterpret_cast(vnode->private_node); + TRACE("volume = %p, vnode = %llu, cookie = %p", volume, inode->ID(), + _cookie); + if (inode->Type() == S_IFDIR || inode->Type() == S_IFLNK) return B_OK; @@ -593,6 +682,9 @@ nfs4_read(fs_volume* volume, fs_vnode* vnode, void* _cookie, off_t pos, { Inode* inode = reinterpret_cast(vnode->private_node); + TRACE("volume = %p, vnode = %llu, cookie = %p, pos = %llu, length = %lu", + volume, inode->ID(), _cookie, pos, *length); + if (inode->Type() == S_IFDIR) return B_IS_A_DIRECTORY; @@ -611,6 +703,9 @@ nfs4_write(fs_volume* volume, fs_vnode* vnode, void* _cookie, off_t pos, { Inode* inode = reinterpret_cast(vnode->private_node); + TRACE("volume = %p, vnode = %llu, cookie = %p, pos = %llu, length = %lu", + volume, inode->ID(), _cookie, pos, *length); + if (inode->Type() == S_IFDIR) return B_IS_A_DIRECTORY; @@ -628,6 +723,7 @@ nfs4_create_dir(fs_volume* volume, fs_vnode* parent, const char* name, int mode) { Inode* inode = reinterpret_cast(parent->private_node); + TRACE("volume = %p, parent = %llu, mode = %d", volume, inode->ID(), mode); return inode->CreateDir(name, mode); } @@ -636,6 +732,7 @@ static status_t nfs4_remove_dir(fs_volume* volume, fs_vnode* parent, const char* name) { Inode* inode = reinterpret_cast(parent->private_node); + TRACE("volume = %p, parent = %llu, name = %s", volume, inode->ID(), name); ino_t id; status_t result = inode->Remove(name, NF4DIR, &id); if (result != B_OK) @@ -653,10 +750,13 @@ nfs4_open_dir(fs_volume* volume, fs_vnode* vnode, void** _cookie) *_cookie = cookie; Inode* inode = reinterpret_cast(vnode->private_node); + TRACE("volume = %p, vnode = %llu", volume, inode->ID()); status_t result = inode->OpenDir(cookie); if (result != B_OK) delete cookie; + TRACE("*cookie = %p", *_cookie); + return result; } @@ -664,6 +764,9 @@ nfs4_open_dir(fs_volume* volume, fs_vnode* vnode, void** _cookie) static status_t nfs4_close_dir(fs_volume* volume, fs_vnode* vnode, void* _cookie) { + TRACE("volume = %p, vnode = %llu, cookie = %p", volume, + reinterpret_cast(vnode->private_node)->ID(), _cookie); + Cookie* cookie = reinterpret_cast(_cookie); return cookie->CancelAll(); } @@ -672,6 +775,9 @@ nfs4_close_dir(fs_volume* volume, fs_vnode* vnode, void* _cookie) static status_t nfs4_free_dir_cookie(fs_volume* volume, fs_vnode* vnode, void* cookie) { + TRACE("volume = %p, vnode = %llu, cookie = %p", volume, + reinterpret_cast(vnode->private_node)->ID(), cookie); + delete reinterpret_cast(cookie); return B_OK; } @@ -683,6 +789,10 @@ nfs4_read_dir(fs_volume* volume, fs_vnode* vnode, void* _cookie, { OpenDirCookie* cookie = reinterpret_cast(_cookie); Inode* inode = reinterpret_cast(vnode->private_node); + + TRACE("volume = %p, vnode = %llu, cookie = %p", volume, inode->ID(), + _cookie); + return inode->ReadDir(buffer, bufferSize, _num, cookie); } @@ -690,6 +800,9 @@ nfs4_read_dir(fs_volume* volume, fs_vnode* vnode, void* _cookie, static status_t nfs4_rewind_dir(fs_volume* volume, fs_vnode* vnode, void* _cookie) { + TRACE("volume = %p, vnode = %llu, cookie = %p", volume, + reinterpret_cast(vnode->private_node)->ID(), _cookie); + OpenDirCookie* cookie = reinterpret_cast(_cookie); cookie->fSpecial = 0; cookie->fCurrent = NULL; @@ -708,6 +821,7 @@ nfs4_open_attr_dir(fs_volume* volume, fs_vnode* vnode, void** _cookie) *_cookie = cookie; Inode* inode = reinterpret_cast(vnode->private_node); + TRACE("volume = %p, vnode = %llu", volume, inode->ID()); status_t result = inode->OpenAttrDir(cookie); if (result != B_OK) delete cookie; @@ -869,6 +983,8 @@ nfs4_test_lock(fs_volume* volume, fs_vnode* vnode, void* _cookie, { Inode* inode = reinterpret_cast(vnode->private_node); OpenFileCookie* cookie = reinterpret_cast(_cookie); + TRACE("volume = %p, vnode = %llu, cookie = %p, lock = %p", volume, + inode->ID(), _cookie, lock); return inode->TestLock(cookie, lock); } @@ -879,6 +995,8 @@ nfs4_acquire_lock(fs_volume* volume, fs_vnode* vnode, void* _cookie, { Inode* inode = reinterpret_cast(vnode->private_node); OpenFileCookie* cookie = reinterpret_cast(_cookie); + TRACE("volume = %p, vnode = %llu, cookie = %p, lock = %p", volume, + inode->ID(), _cookie, lock); inode->RevalidateFileCache(); @@ -891,6 +1009,8 @@ nfs4_release_lock(fs_volume* volume, fs_vnode* vnode, void* _cookie, const struct flock* lock) { Inode* inode = reinterpret_cast(vnode->private_node); + TRACE("volume = %p, vnode = %llu, cookie = %p, lock = %p", volume, + inode->ID(), _cookie, lock); if (inode->Type() == S_IFDIR || inode->Type() == S_IFLNK) return B_OK; From 81f2b97177995973754f099b35a0cdb66762508d Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Thu, 1 Nov 2012 18:31:04 +0100 Subject: [PATCH 213/252] nfs4: Fix race condition between inode creation and removal If the underlying file system reuses inode numbers it is possible that an entry of inode with reused id in InodeIdMap will be removed. This patch should also improve behavior when one of many hard links is removed. --- .../kernel/file_systems/nfs4/FileSystem.cpp | 2 + .../kernel/file_systems/nfs4/FileSystem.h | 2 + .../kernel/file_systems/nfs4/Inode.cpp | 2 + .../kernel/file_systems/nfs4/InodeIdMap.h | 53 ++++++++++++++++--- .../file_systems/nfs4/kernel_interface.cpp | 31 +++++++++-- 5 files changed, 80 insertions(+), 10 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp b/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp index 66bb163f33..c68bfeda33 100644 --- a/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp @@ -41,6 +41,7 @@ FileSystem::FileSystem(const MountConfiguration& configuration) mutex_init(&fOpenOwnerLock, NULL); mutex_init(&fOpenLock, NULL); mutex_init(&fDelegationLock, NULL); + rw_lock_init(&fRemoveNodeLock, NULL); } @@ -48,6 +49,7 @@ FileSystem::~FileSystem() { NFSServer()->RemoveFileSystem(this); + rw_lock_destroy(&fRemoveNodeLock); mutex_destroy(&fDelegationLock); mutex_destroy(&fOpenLock); mutex_destroy(&fOpenOwnerLock); diff --git a/src/add-ons/kernel/file_systems/nfs4/FileSystem.h b/src/add-ons/kernel/file_systems/nfs4/FileSystem.h index 2937066e41..f99232d315 100644 --- a/src/add-ons/kernel/file_systems/nfs4/FileSystem.h +++ b/src/add-ons/kernel/file_systems/nfs4/FileSystem.h @@ -78,6 +78,8 @@ public: FileSystem* fNext; FileSystem* fPrev; + + rw_lock fRemoveNodeLock; private: FileSystem(const MountConfiguration& config); diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index ab9cbf4cb3..f303dfda43 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -281,6 +281,8 @@ Inode::Remove(const char* name, FileType type, ino_t* id) status_t result = NFS4Inode::RemoveObject(name, type, &changeInfo, &fileID); if (result != B_OK) return result; + if (type != NF4NAMEDATTR) + fFileSystem->InoIdMap()->MarkRemoved(fileID); DirectoryCache* cache = type != NF4NAMEDATTR ? fCache : fAttrCache; cache->Lock(); diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeIdMap.h b/src/add-ons/kernel/file_systems/nfs4/InodeIdMap.h index a6bbd48704..2bad259d95 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeIdMap.h +++ b/src/add-ons/kernel/file_systems/nfs4/InodeIdMap.h @@ -16,6 +16,10 @@ #include "FileInfo.h" +struct InodeIdMapEntry { + FileInfo fFileInfo; + bool fRemoved; +}; class InodeIdMap { public: @@ -24,11 +28,15 @@ public: inline status_t AddEntry(const FileInfo& fi, ino_t id, bool weak = false); + inline status_t MarkRemoved(ino_t id); inline status_t RemoveEntry(ino_t id); inline status_t GetFileInfo(FileInfo* fi, ino_t id); +protected: + inline bool _IsEntryRemoved(ino_t id); + private: - AVLTreeMap fMap; + AVLTreeMap fMap; mutex fLock; }; @@ -51,10 +59,29 @@ InodeIdMap::~InodeIdMap() inline status_t InodeIdMap::AddEntry(const FileInfo& fi, ino_t id, bool weak) { + InodeIdMapEntry entry; + MutexLocker _(fLock); - //if (weak) + if (weak || _IsEntryRemoved(id)) fMap.Remove(id); - return fMap.Insert(id, fi); + + entry.fFileInfo = fi; + entry.fRemoved = false; + + return fMap.Insert(id, entry); +} + + +inline status_t +InodeIdMap::MarkRemoved(ino_t id) +{ + MutexLocker _(fLock); + AVLTreeMap::Iterator it = fMap.Find(id); + if (!it.HasCurrent()) + return B_ENTRY_NOT_FOUND; + + it.CurrentValuePointer()->fRemoved = true; + return B_OK; } @@ -62,7 +89,9 @@ inline status_t InodeIdMap::RemoveEntry(ino_t id) { MutexLocker _(fLock); - return fMap.Remove(id); + if (_IsEntryRemoved(id)) + return fMap.Remove(id); + return B_OK; } @@ -72,14 +101,26 @@ InodeIdMap::GetFileInfo(FileInfo* fi, ino_t id) ASSERT(fi != NULL); MutexLocker _(fLock); - AVLTreeMap::Iterator it = fMap.Find(id); + AVLTreeMap::Iterator it = fMap.Find(id); if (!it.HasCurrent()) return B_ENTRY_NOT_FOUND; - *fi = it.Current(); + *fi = it.Current().fFileInfo; return B_OK; } +// Caller must hold fLock +inline bool +InodeIdMap::_IsEntryRemoved(ino_t id) +{ + AVLTreeMap::Iterator it = fMap.Find(id); + if (!it.HasCurrent()) + return true; + + return it.Current().fRemoved; +} + + #endif // INODEIDMAP_H 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 498d1e5f2c..66302a8801 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -25,7 +25,9 @@ #include "RPCServer.h" #include "WorkQueue.h" +#ifdef DEBUG #define TRACE_NFS4 +#endif #ifdef TRACE_NFS4 static mutex gTraceLock = MUTEX_INITIALIZER(NULL); @@ -33,7 +35,7 @@ static mutex gTraceLock = MUTEX_INITIALIZER(NULL); #define TRACE(x...) \ { \ mutex_lock(&gTraceLock); \ - dprintf("%s(): ", __FUNCTION__); \ + dprintf("nfs4: %s(): ", __FUNCTION__); \ dprintf(x); \ dprintf("\n"); \ mutex_unlock(&gTraceLock); \ @@ -251,10 +253,13 @@ nfs4_read_fs_info(fs_volume* volume, struct fs_info* info) static status_t nfs4_lookup(fs_volume* volume, fs_vnode* dir, const char* name, ino_t* _id) { + FileSystem* fs = reinterpret_cast(volume->private_volume); Inode* inode = reinterpret_cast(dir->private_node); - + TRACE("volume = %p, dir = %llu, name = %s", volume, inode->ID(), name); + ReadLocker(fs->fRemoveNodeLock); + status_t result = inode->LookUp(name, _id); if (result != B_OK) return result; @@ -262,7 +267,9 @@ nfs4_lookup(fs_volume* volume, fs_vnode* dir, const char* name, ino_t* _id) void* ptr; TRACE("*_id = %llu", *_id); - return get_vnode(volume, *_id, &ptr); + result = get_vnode(volume, *_id, &ptr); + unremove_vnode(volume, *_id); + return result; } @@ -485,9 +492,12 @@ static status_t nfs4_unlink(fs_volume* volume, fs_vnode* dir, const char* name) { Inode* inode = reinterpret_cast(dir->private_node); + FileSystem* fs = reinterpret_cast(volume->private_volume); TRACE("volume = %p, dir = %llu, name = %s", volume, inode->ID(), name); + WriteLocker(fs->fRemoveNodeLock); + ino_t id; status_t result = inode->Remove(name, NF4REG, &id); if (result != B_OK) @@ -503,11 +513,14 @@ nfs4_rename(fs_volume* volume, fs_vnode* fromDir, const char* fromName, { Inode* fromInode = reinterpret_cast(fromDir->private_node); Inode* toInode = reinterpret_cast(toDir->private_node); + FileSystem* fs = reinterpret_cast(volume->private_volume); TRACE("volume = %p, fromDir = %llu, toDir = %llu, fromName = %s, " \ "toName = %s", volume, fromInode->ID(), toInode->ID(), fromName, toName); + ReadLocker(fs->fRemoveNodeLock); + ino_t id; status_t result = Inode::Rename(fromInode, toInode, fromName, toName, false, &id); @@ -517,6 +530,8 @@ nfs4_rename(fs_volume* volume, fs_vnode* fromDir, const char* fromName, Inode* child; result = get_vnode(volume, id, reinterpret_cast(&child)); if (result == B_OK) { + unremove_vnode(volume, id); + child->fInfo.fParent = toInode->fInfo.fHandle; child->fInfo.CreateName(toInode->fInfo.fPath, toName); } @@ -564,10 +579,13 @@ nfs4_create(fs_volume* volume, fs_vnode* dir, const char* name, int openMode, *_cookie = cookie; Inode* inode = reinterpret_cast(dir->private_node); + FileSystem* fs = reinterpret_cast(volume->private_volume); TRACE("volume = %p, dir = %llu, name = %s, openMode = %d, perms = %d", volume, inode->ID(), name, openMode, perms); + ReadLocker(fs->fRemoveNodeLock); + OpenDelegationData data; status_t result = inode->Create(name, openMode, perms, cookie, &data, _newVnodeID); @@ -591,7 +609,8 @@ nfs4_create(fs_volume* volume, fs_vnode* dir, const char* name, int openMode, delete cookie; return result; } - } + } else + unremove_vnode(volume, *_newVnodeID); child->SetOpenState(cookie->fOpenState); @@ -732,7 +751,11 @@ static status_t nfs4_remove_dir(fs_volume* volume, fs_vnode* parent, const char* name) { Inode* inode = reinterpret_cast(parent->private_node); + FileSystem* fs = reinterpret_cast(volume->private_volume); + TRACE("volume = %p, parent = %llu, name = %s", volume, inode->ID(), name); + WriteLocker(fs->fRemoveNodeLock); + ino_t id; status_t result = inode->Remove(name, NF4DIR, &id); if (result != B_OK) From 2f44d34e5e696fe1fde8f4a8ee2728664984db04 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Fri, 2 Nov 2012 16:14:07 +0100 Subject: [PATCH 214/252] nfs4: Reset object_wait_info.events in each iteration --- .../kernel/file_systems/nfs4/Connection.cpp | 16 +++++++++++++++- .../kernel/file_systems/nfs4/RPCServer.cpp | 5 +++-- .../kernel/file_systems/nfs4/WorkQueue.cpp | 2 +- 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Connection.cpp b/src/add-ons/kernel/file_systems/nfs4/Connection.cpp index 70eb4fe20d..7191a8d1b7 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Connection.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Connection.cpp @@ -372,6 +372,9 @@ ConnectionStream::Receive(void** _buffer, uint32* _size) object[1].events = B_EVENT_READ; do { + object[0].events = B_EVENT_ACQUIRE_SEMAPHORE; + object[1].events = B_EVENT_READ; + result = wait_for_objects(object, 2); if (result < B_OK || (object[0].events & B_EVENT_ACQUIRE_SEMAPHORE) != 0) { @@ -383,7 +386,7 @@ ConnectionStream::Receive(void** _buffer, uint32* _size) // There is only one listener thread per connection. No need to lock. uint32 received = 0; do { - result = recv(fSocket, &record_size + received, + result = recv(fSocket, ((uint8*)&record_size) + received, sizeof(record_size) - received, 0); received += result; } while (result > 0 && received < sizeof(record_size)); @@ -397,6 +400,8 @@ ConnectionStream::Receive(void** _buffer, uint32* _size) } record_size = ntohl(record_size); + ASSERT(record_size > 0); + last_one = static_cast(record_size) < 0; record_size &= LAST_FRAGMENT - 1; @@ -417,6 +422,9 @@ ConnectionStream::Receive(void** _buffer, uint32* _size) result = errno; free(buffer); return result; + } else if (result == 0) { + free(buffer); + return ECONNABORTED; } size += record_size; @@ -453,6 +461,9 @@ ConnectionPacket::Receive(void** _buffer, uint32* _size) object[1].events = B_EVENT_READ; do { + object[0].events = B_EVENT_ACQUIRE_SEMAPHORE; + object[1].events = B_EVENT_READ; + result = wait_for_objects(object, 2); if (result < B_OK || (object[0].events & B_EVENT_ACQUIRE_SEMAPHORE) != 0) { @@ -719,6 +730,9 @@ ConnectionListener::AcceptConnection(Connection** connection) object[1].events = B_EVENT_READ; do { + object[0].events = B_EVENT_ACQUIRE_SEMAPHORE; + object[1].events = B_EVENT_READ; + status_t result = wait_for_objects(object, 2); if (result < B_OK || (object[0].events & B_EVENT_ACQUIRE_SEMAPHORE) != 0) { diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp b/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp index de2faf589a..a8ae352370 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp @@ -265,7 +265,7 @@ Server::_Listener() { status_t result; uint32 size; - void* buffer; + void* buffer = NULL; while (!fThreadCancel) { result = fConnection->Receive(&buffer, &size); @@ -275,7 +275,8 @@ Server::_Listener() fThreadError = result; return result; } - + + ASSERT(buffer != NULL && size > 0); Reply* reply = new(std::nothrow) Reply(buffer, size); if (reply == NULL) { free(buffer); diff --git a/src/add-ons/kernel/file_systems/nfs4/WorkQueue.cpp b/src/add-ons/kernel/file_systems/nfs4/WorkQueue.cpp index 8806436351..0e00775451 100644 --- a/src/add-ons/kernel/file_systems/nfs4/WorkQueue.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/WorkQueue.cpp @@ -115,8 +115,8 @@ void WorkQueue::DequeueJob() { MutexLocker locker(fQueueLock); - WorkQueueEntry* entry = fQueue.RemoveHead(); + locker.Unlock(); ASSERT(entry != NULL); void* args = entry->fArguments; From fa5d300d6b01032ece3f4d2dcf2391b6cc9a6ef1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Revol?= Date: Fri, 24 Aug 2012 03:30:51 +0200 Subject: [PATCH 215/252] nfs4: Fix timespec attribute allocation size MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * copying the time attributes was fixed to copy the whole st_?tim timespec struct but the allocation size was still only that of st_?time subfield, which is only a time_t. Signed-off-by: François Revol Signed-off-by: Pawel Dziepak --- src/add-ons/kernel/file_systems/nfs4/Inode.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index f303dfda43..31c519f8e3 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -628,16 +628,16 @@ Inode::WriteStat(const struct stat* st, uint32 mask, OpenAttrCookie* cookie) if ((mask & B_STAT_ACCESS_TIME) != 0) { attr[i].fAttribute = FATTR4_TIME_ACCESS_SET; attr[i].fFreePointer = true; - attr[i].fData.fPointer = malloc(sizeof(st->st_atime)); - memcpy(attr[i].fData.fPointer, &st->st_atime, sizeof(st->st_atim)); + attr[i].fData.fPointer = malloc(sizeof(st->st_atim)); + memcpy(attr[i].fData.fPointer, &st->st_atim, sizeof(st->st_atim)); i++; } if ((mask & B_STAT_MODIFICATION_TIME) != 0) { attr[i].fAttribute = FATTR4_TIME_MODIFY_SET; attr[i].fFreePointer = true; - attr[i].fData.fPointer = malloc(sizeof(st->st_mtime)); - memcpy(attr[i].fData.fPointer, &st->st_mtime, sizeof(st->st_mtim)); + attr[i].fData.fPointer = malloc(sizeof(st->st_mtim)); + memcpy(attr[i].fData.fPointer, &st->st_mtim, sizeof(st->st_mtim)); i++; } From b352cbf6ca8ed101ac83e0f87747b8be47dda1df Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Mon, 3 Dec 2012 17:38:34 +0100 Subject: [PATCH 216/252] nfs4: Introduce VnodeToInode mapping VnodeToInode is another abstraction layer between VFS vnodes and NFS nodes. It simplifies dealing with race conditions as well as faking some guarantees VFS expects but NFS does not provide. --- .../kernel/file_systems/nfs4/FileSystem.cpp | 2 - .../kernel/file_systems/nfs4/FileSystem.h | 2 - .../kernel/file_systems/nfs4/Inode.cpp | 15 +- src/add-ons/kernel/file_systems/nfs4/Inode.h | 7 +- .../kernel/file_systems/nfs4/InodeDir.cpp | 4 +- .../kernel/file_systems/nfs4/InodeIdMap.h | 2 +- src/add-ons/kernel/file_systems/nfs4/Jamfile | 1 + .../kernel/file_systems/nfs4/VnodeToInode.cpp | 40 ++ .../kernel/file_systems/nfs4/VnodeToInode.h | 115 ++++ .../file_systems/nfs4/kernel_interface.cpp | 554 +++++++++++++----- 10 files changed, 584 insertions(+), 158 deletions(-) create mode 100644 src/add-ons/kernel/file_systems/nfs4/VnodeToInode.cpp create mode 100644 src/add-ons/kernel/file_systems/nfs4/VnodeToInode.h diff --git a/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp b/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp index c68bfeda33..66bb163f33 100644 --- a/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp @@ -41,7 +41,6 @@ FileSystem::FileSystem(const MountConfiguration& configuration) mutex_init(&fOpenOwnerLock, NULL); mutex_init(&fOpenLock, NULL); mutex_init(&fDelegationLock, NULL); - rw_lock_init(&fRemoveNodeLock, NULL); } @@ -49,7 +48,6 @@ FileSystem::~FileSystem() { NFSServer()->RemoveFileSystem(this); - rw_lock_destroy(&fRemoveNodeLock); mutex_destroy(&fDelegationLock); mutex_destroy(&fOpenLock); mutex_destroy(&fOpenOwnerLock); diff --git a/src/add-ons/kernel/file_systems/nfs4/FileSystem.h b/src/add-ons/kernel/file_systems/nfs4/FileSystem.h index f99232d315..2937066e41 100644 --- a/src/add-ons/kernel/file_systems/nfs4/FileSystem.h +++ b/src/add-ons/kernel/file_systems/nfs4/FileSystem.h @@ -78,8 +78,6 @@ public: FileSystem* fNext; FileSystem* fPrev; - - rw_lock fRemoveNodeLock; private: FileSystem(const MountConfiguration& config); diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index 31c519f8e3..1c30888247 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -184,11 +184,6 @@ Inode::LookUp(const char* name, ino_t* id) if (fType != NF4DIR) return B_NOT_A_DIRECTORY; - if (!strcmp(name, ".")) { - *id = ID(); - return B_OK; - } - uint64 change; uint64 fileID; FileHandle handle; @@ -281,8 +276,6 @@ Inode::Remove(const char* name, FileType type, ino_t* id) status_t result = NFS4Inode::RemoveObject(name, type, &changeInfo, &fileID); if (result != B_OK) return result; - if (type != NF4NAMEDATTR) - fFileSystem->InoIdMap()->MarkRemoved(fileID); DirectoryCache* cache = type != NF4NAMEDATTR ? fCache : fAttrCache; cache->Lock(); @@ -395,14 +388,15 @@ Inode::Rename(Inode* from, Inode* to, const char* fromName, const char* toName, status_t -Inode::CreateLink(const char* name, const char* path, int mode) +Inode::CreateLink(const char* name, const char* path, int mode, ino_t* id) { - return CreateObject(name, path, mode, NF4LNK); + return CreateObject(name, path, mode, NF4LNK, id); } status_t -Inode::CreateObject(const char* name, const char* path, int mode, FileType type) +Inode::CreateObject(const char* name, const char* path, int mode, FileType type, + ino_t* id) { ASSERT(name != NULL); ASSERT(type != NF4LNK || path != NULL); @@ -435,6 +429,7 @@ Inode::CreateObject(const char* name, const char* path, int mode, FileType type) notify_entry_created(fFileSystem->DevId(), ID(), name, FileIdToInoT(fileID)); + *id = FileIdToInoT(fileID); 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 190154f713..521e1d75d9 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -51,10 +51,10 @@ public: status_t SyncAndCommit(bool force = false); status_t CreateObject(const char* name, const char* path, - int mode, FileType type); + int mode, FileType type, ino_t* id); status_t CreateLink(const char* name, const char* path, - int mode); + int mode, ino_t* id); status_t Link(Inode* dir, const char* name); status_t Remove(const char* name, FileType type, @@ -89,7 +89,8 @@ public: status_t WriteDirect(OpenStateCookie* cookie, off_t pos, const void* buffer, size_t* _length); - status_t CreateDir(const char* name, int mode); + status_t CreateDir(const char* name, int mode, + ino_t* id); status_t OpenDir(OpenDirCookie* cookie); status_t ReadDir(void* buffer, uint32 size, uint32* count, OpenDirCookie* cookie); diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp b/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp index 909696cac7..508b5c8c22 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp @@ -18,9 +18,9 @@ status_t -Inode::CreateDir(const char* name, int mode) +Inode::CreateDir(const char* name, int mode, ino_t* id) { - return CreateObject(name, NULL, mode, NF4DIR); + return CreateObject(name, NULL, mode, NF4DIR, id); } diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeIdMap.h b/src/add-ons/kernel/file_systems/nfs4/InodeIdMap.h index 2bad259d95..43ae7994b2 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeIdMap.h +++ b/src/add-ons/kernel/file_systems/nfs4/InodeIdMap.h @@ -62,7 +62,7 @@ InodeIdMap::AddEntry(const FileInfo& fi, ino_t id, bool weak) InodeIdMapEntry entry; MutexLocker _(fLock); - if (weak || _IsEntryRemoved(id)) + if (!weak || _IsEntryRemoved(id)) fMap.Remove(id); entry.fFileInfo = fi; diff --git a/src/add-ons/kernel/file_systems/nfs4/Jamfile b/src/add-ons/kernel/file_systems/nfs4/Jamfile index 246ba99d2a..c77e63402f 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Jamfile +++ b/src/add-ons/kernel/file_systems/nfs4/Jamfile @@ -35,6 +35,7 @@ KernelAddon nfs4 : RPCCallbackServer.cpp RPCReply.cpp RPCServer.cpp + VnodeToInode.cpp WorkQueue.cpp XDR.cpp ; diff --git a/src/add-ons/kernel/file_systems/nfs4/VnodeToInode.cpp b/src/add-ons/kernel/file_systems/nfs4/VnodeToInode.cpp new file mode 100644 index 0000000000..42b3461058 --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/VnodeToInode.cpp @@ -0,0 +1,40 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ + + +#include "VnodeToInode.h" + + +Inode* +VnodeToInode::Get() +{ + if (fInode == NULL) { + status_t result = fFileSystem->GetInode(fID, &fInode); + if (result != B_OK) + fInode = NULL; + } + + return fInode; +} + + +void +VnodeToInode::Replace(Inode* newInode) +{ + WriteLocker _(fLock); + if (fInode != NULL) + fInode->GetFileSystem()->InoIdMap()->MarkRemoved(fID); + delete fInode; + + fInode = newInode; + if (fInode != NULL) { + ASSERT(fFileSystem == fInode->GetFileSystem()); + fInode->GetFileSystem()->InoIdMap()->AddEntry(fInode->fInfo, fID); + } +} + diff --git a/src/add-ons/kernel/file_systems/nfs4/VnodeToInode.h b/src/add-ons/kernel/file_systems/nfs4/VnodeToInode.h new file mode 100644 index 0000000000..f0a39e78e0 --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/VnodeToInode.h @@ -0,0 +1,115 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ +#ifndef VNODETOINODE_H +#define VNODETOINODE_H + +#include +#include +#include + +#include "Inode.h" +#include "InodeIdMap.h" + +class VnodeToInode { +public: + inline VnodeToInode(ino_t id, FileSystem* fileSystem); + inline ~VnodeToInode(); + + inline void Lock(); + inline void Unlock(); + + Inode* Get(); + void Replace(Inode* newInode); + + inline void Remove(); + inline void Clear(); + + inline ino_t ID(); +private: + ino_t fID; + rw_lock fLock; + + Inode* fInode; + FileSystem* fFileSystem; +}; + +class VnodeToInodeLocking { +public: + inline bool Lock(VnodeToInode* vti) + { + vti->Lock(); + return true; + } + + inline void Unlock(VnodeToInode* vti) + { + vti->Unlock(); + } +}; + +typedef AutoLocker VnodeToInodeLocker; + +inline +VnodeToInode::VnodeToInode(ino_t id, FileSystem* fileSystem) + : + fID(id), + fInode(NULL), + fFileSystem(fileSystem) +{ + rw_lock_init(&fLock, NULL); +} + + +inline +VnodeToInode::~VnodeToInode() +{ + Remove(); + if (fFileSystem != NULL) + fFileSystem->InoIdMap()->RemoveEntry(fID); + rw_lock_destroy(&fLock); +} + + +inline void +VnodeToInode::Lock() +{ + rw_lock_read_lock(&fLock); +} + + +inline void +VnodeToInode::Unlock() +{ + rw_lock_read_unlock(&fLock); +} + + +inline void +VnodeToInode::Remove() +{ + Replace(NULL); +} + + +inline void +VnodeToInode::Clear() +{ + WriteLocker _(fLock); + delete fInode; + fInode = NULL; +} + + +inline ino_t +VnodeToInode::ID() +{ + return fID; +} + +#endif // VNODETOINODE_H + 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 66302a8801..8045a8b67f 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -23,6 +23,7 @@ #include "RootInode.h" #include "RPCCallbackServer.h" #include "RPCServer.h" +#include "VnodeToInode.h" #include "WorkQueue.h" #ifdef DEBUG @@ -190,7 +191,15 @@ nfs4_mount(fs_volume* volume, const char* device, uint32 flags, volume->private_volume = fs; volume->ops = &gNFSv4VolumeOps; - result = publish_vnode(volume, inode->ID(), inode, &gNFSv4VnodeOps, + VnodeToInode* vti = new VnodeToInode(inode->ID(), fs); + if (vti == NULL) { + delete fs; + gRPCServerManager->Release(server); + return B_NO_MEMORY; + } + + vti->Replace(inode); + result = publish_vnode(volume, inode->ID(), vti, &gNFSv4VnodeOps, inode->Type(), 0); if (result != B_OK) return result; @@ -207,16 +216,21 @@ static status_t nfs4_get_vnode(fs_volume* volume, ino_t id, fs_vnode* vnode, int* _type, uint32* _flags, bool reenter) { + FileSystem* fs = reinterpret_cast(volume->private_volume); TRACE("volume = %p, id = %llu", volume, id); - FileSystem* fs = reinterpret_cast(volume->private_volume); + VnodeToInode* vnodeToInode = new VnodeToInode(id, fs); + if (vnodeToInode == NULL) + return B_NO_MEMORY; + Inode* inode; status_t result = fs->GetInode(id, &inode); if (result != B_OK) return result; + vnodeToInode->Replace(inode); vnode->ops = &gNFSv4VnodeOps; - vnode->private_node = inode; + vnode->private_node = vnodeToInode; *_type = inode->Type(); *_flags = 0; @@ -253,22 +267,39 @@ nfs4_read_fs_info(fs_volume* volume, struct fs_info* info) static status_t nfs4_lookup(fs_volume* volume, fs_vnode* dir, const char* name, ino_t* _id) { - FileSystem* fs = reinterpret_cast(volume->private_volume); - Inode* inode = reinterpret_cast(dir->private_node); - - TRACE("volume = %p, dir = %llu, name = %s", volume, inode->ID(), name); + VnodeToInode* vti = reinterpret_cast(dir->private_node); - ReadLocker(fs->fRemoveNodeLock); + if (!strcmp(name, ".")) { + *_id = vti->ID(); + void* ptr; + return get_vnode(volume, *_id, &ptr); + } + + VnodeToInodeLocker locker(vti); + + Inode* inode = vti->Get(); + if (inode == NULL) + return B_ENTRY_NOT_FOUND; + + TRACE("volume = %p, dir = %llu, name = %s", volume, vti->ID(), name); status_t result = inode->LookUp(name, _id); if (result != B_OK) return result; - - void* ptr; + locker.Unlock(); TRACE("*_id = %llu", *_id); + + // If VTI holds an outdated Inode next operation performed on it will + // return either ERR_STALE or ERR_FHEXPIRED. Both of these error codes + // will cause FileInfo data to be updated (the former will also cause Inode + // object to be recreated). We are taking an optimistic (an lazy) approach + // here. The following code just ensures VTI won't be removed too soon. + void* ptr; result = get_vnode(volume, *_id, &ptr); - unremove_vnode(volume, *_id); + if (result == B_OK) + unremove_vnode(volume, *_id); + return result; } @@ -277,9 +308,13 @@ static status_t nfs4_get_vnode_name(fs_volume* volume, fs_vnode* vnode, char* buffer, size_t bufferSize) { - Inode* inode = reinterpret_cast(vnode->private_node); + VnodeToInode* vti = reinterpret_cast(vnode->private_node); + TRACE("volume = %p, vnode = %llu", volume, vti->ID()); - TRACE("volume = %p, vnode = %llu", volume, inode->ID()); + VnodeToInodeLocker _(vti); + Inode* inode = vti->Get(); + if (inode == NULL) + return B_ENTRY_NOT_FOUND; strncpy(buffer, inode->Name(), bufferSize); return B_OK; @@ -289,17 +324,10 @@ nfs4_get_vnode_name(fs_volume* volume, fs_vnode* vnode, char* buffer, static status_t nfs4_put_vnode(fs_volume* volume, fs_vnode* vnode, bool reenter) { - FileSystem* fs = reinterpret_cast(volume->private_volume); - Inode* inode = reinterpret_cast(vnode->private_node); - - TRACE("volume = %p, vnode = %llu", volume, inode->ID()); - - if (fs->Root() == inode) - return B_OK; - - inode->GetFileSystem()->InoIdMap()->RemoveEntry(inode->ID()); - delete inode; + VnodeToInode* vti = reinterpret_cast(vnode->private_node); + TRACE("volume = %p, vnode = %llu", volume, vti->ID()); + delete vti; return B_OK; } @@ -307,20 +335,15 @@ nfs4_put_vnode(fs_volume* volume, fs_vnode* vnode, bool reenter) static status_t nfs4_remove_vnode(fs_volume* volume, fs_vnode* vnode, bool reenter) { - // It is the server that actually deletes a node. Nodes on client - // side are only an attempt to simulate local filesystem. Hence, - // this hook is the same as put_vnode(). - FileSystem* fs = reinterpret_cast(volume->private_volume); - Inode* inode = reinterpret_cast(vnode->private_node); + VnodeToInode* vti = reinterpret_cast(vnode->private_node); + TRACE("volume = %p, vnode = %llu", volume, vti->ID()); - TRACE("volume = %p, vnode = %llu", volume, inode->ID()); - - if (fs->Root() == inode) + if (fs->Root() == vti->Get()) return B_OK; - inode->GetFileSystem()->InoIdMap()->RemoveEntry(inode->ID()); - delete inode; + ASSERT(vti->Get() == NULL); + delete vti; return B_OK; } @@ -330,12 +353,16 @@ static status_t nfs4_read_pages(fs_volume* _volume, fs_vnode* vnode, void* _cookie, off_t pos, const iovec* vecs, size_t count, size_t* _numBytes) { - Inode* inode = reinterpret_cast(vnode->private_node); - + VnodeToInode* vti = reinterpret_cast(vnode->private_node); TRACE("volume = %p, vnode = %llu, cookie = %p, pos = %llu, " \ - "count = %lu, numBytes = %lu", _volume, inode->ID(), _cookie, pos, + "count = %lu, numBytes = %lu", _volume, vti->ID(), _cookie, pos, count, *_numBytes); + VnodeToInodeLocker _(vti); + Inode* inode = vti->Get(); + if (inode == NULL) + return B_ENTRY_NOT_FOUND; + OpenFileCookie* cookie = reinterpret_cast(_cookie); status_t result; @@ -370,12 +397,16 @@ static status_t nfs4_write_pages(fs_volume* _volume, fs_vnode* vnode, void* _cookie, off_t pos, const iovec* vecs, size_t count, size_t* _numBytes) { - Inode* inode = reinterpret_cast(vnode->private_node); - + VnodeToInode* vti = reinterpret_cast(vnode->private_node); TRACE("volume = %p, vnode = %llu, cookie = %p, pos = %llu, " \ - "count = %lu, numBytes = %lu", _volume, inode->ID(), _cookie, pos, + "count = %lu, numBytes = %lu", _volume, vti->ID(), _cookie, pos, count, *_numBytes); + VnodeToInodeLocker _(vti); + Inode* inode = vti->Get(); + if (inode == NULL) + return B_ENTRY_NOT_FOUND; + OpenFileCookie* cookie = reinterpret_cast(_cookie); status_t result; @@ -406,11 +437,15 @@ nfs4_write_pages(fs_volume* _volume, fs_vnode* vnode, void* _cookie, off_t pos, static status_t nfs4_io(fs_volume* volume, fs_vnode* vnode, void* cookie, io_request* request) { - Inode* inode = reinterpret_cast(vnode->private_node); - - TRACE("volume = %p, vnode = %llu, cookie = %p", volume, inode->ID(), + VnodeToInode* vti = reinterpret_cast(vnode->private_node); + TRACE("volume = %p, vnode = %llu, cookie = %p", volume, vti->ID(), cookie); + VnodeToInodeLocker _(vti); + Inode* inode = vti->Get(); + if (inode == NULL) + return B_ENTRY_NOT_FOUND; + IORequestArgs* args = new(std::nothrow) IORequestArgs; if (args == NULL) { notify_io_request(request, B_NO_MEMORY); @@ -439,7 +474,8 @@ static status_t nfs4_set_flags(fs_volume* volume, fs_vnode* vnode, void* _cookie, int flags) { TRACE("volume = %p, vnode = %llu, cookie = %p, flags = %d", volume, - reinterpret_cast(vnode->private_node)->ID(), _cookie, flags); + reinterpret_cast(vnode->private_node)->ID(), _cookie, + flags); OpenFileCookie* cookie = reinterpret_cast(_cookie); cookie->fMode = (cookie->fMode & ~(O_APPEND | O_NONBLOCK)) | flags; @@ -450,8 +486,14 @@ nfs4_set_flags(fs_volume* volume, fs_vnode* vnode, void* _cookie, int flags) static status_t nfs4_fsync(fs_volume* volume, fs_vnode* vnode) { - Inode* inode = reinterpret_cast(vnode->private_node); - TRACE("volume = %p, vnode = %llu", volume, inode->ID()); + VnodeToInode* vti = reinterpret_cast(vnode->private_node); + TRACE("volume = %p, vnode = %llu", volume, vti->ID()); + + VnodeToInodeLocker _(vti); + Inode* inode = vti->Get(); + if (inode == NULL) + return B_ENTRY_NOT_FOUND; + return inode->SyncAndCommit(); } @@ -460,8 +502,14 @@ static status_t nfs4_read_symlink(fs_volume* volume, fs_vnode* link, char* buffer, size_t* _bufferSize) { - Inode* inode = reinterpret_cast(link->private_node); - TRACE("volume = %p, link = %llu", volume, inode->ID()); + VnodeToInode* vti = reinterpret_cast(link->private_node); + TRACE("volume = %p, link = %llu", volume, vti->ID()); + + VnodeToInodeLocker _(vti); + Inode* inode = vti->Get(); + if (inode == NULL) + return B_ENTRY_NOT_FOUND; + return inode->ReadLink(buffer, _bufferSize); } @@ -470,20 +518,46 @@ static status_t nfs4_create_symlink(fs_volume* volume, fs_vnode* dir, const char* name, const char* path, int mode) { - Inode* inode = reinterpret_cast(dir->private_node); + VnodeToInode* vti = reinterpret_cast(dir->private_node); TRACE("volume = %p, dir = %llu, name = %s, path = %s, mode = %d", volume, - inode->ID(), name, path, mode); - return inode->CreateLink(name, path, mode); + vti->ID(), name, path, mode); + + VnodeToInodeLocker _(vti); + Inode* inode = vti->Get(); + if (inode == NULL) + return B_ENTRY_NOT_FOUND; + + ino_t id; + status_t result = inode->CreateLink(name, path, mode, &id); + if (result != B_OK) + return result; + + result = get_vnode(volume, id, reinterpret_cast(&vti)); + if (result == B_OK) + vti->Clear(); + return B_OK; } static status_t nfs4_link(fs_volume* volume, fs_vnode* dir, const char* name, fs_vnode* vnode) { - Inode* inode = reinterpret_cast(vnode->private_node); - Inode* dirInode = reinterpret_cast(dir->private_node); + VnodeToInode* vti = reinterpret_cast(vnode->private_node); + VnodeToInode* dirVti = reinterpret_cast(dir->private_node); TRACE("volume = %p, dir = %llu, name = %s, vnode = %llu", volume, - dirInode->ID(), name, inode->ID()); + dirVti->ID(), name, vti->ID()); + + VnodeToInodeLocker _dir(dirVti); + Inode* dirInode = dirVti->Get(); + if (dirInode == NULL) + return B_ENTRY_NOT_FOUND; + + + VnodeToInodeLocker _(vti); + Inode* inode = vti->Get(); + if (inode == NULL) + return B_ENTRY_NOT_FOUND; + return inode->Link(dirInode, name); } @@ -491,17 +565,27 @@ nfs4_link(fs_volume* volume, fs_vnode* dir, const char* name, fs_vnode* vnode) static status_t nfs4_unlink(fs_volume* volume, fs_vnode* dir, const char* name) { - Inode* inode = reinterpret_cast(dir->private_node); - FileSystem* fs = reinterpret_cast(volume->private_volume); + VnodeToInode* vti = reinterpret_cast(dir->private_node); - TRACE("volume = %p, dir = %llu, name = %s", volume, inode->ID(), name); + VnodeToInodeLocker locker(vti); + Inode* inode = vti->Get(); + if (inode == NULL) + return B_ENTRY_NOT_FOUND; - WriteLocker(fs->fRemoveNodeLock); + TRACE("volume = %p, dir = %llu, name = %s", volume, vti->ID(), name); ino_t id; status_t result = inode->Remove(name, NF4REG, &id); if (result != B_OK) return result; + locker.Unlock(); + + void* ptr; + result = get_vnode(volume, id, &ptr); + if (result == B_OK) { + vti = reinterpret_cast(ptr); + vti->Remove(); + } return remove_vnode(volume, id); } @@ -511,15 +595,23 @@ static status_t nfs4_rename(fs_volume* volume, fs_vnode* fromDir, const char* fromName, fs_vnode* toDir, const char* toName) { - Inode* fromInode = reinterpret_cast(fromDir->private_node); - Inode* toInode = reinterpret_cast(toDir->private_node); - FileSystem* fs = reinterpret_cast(volume->private_volume); - + VnodeToInode* fromVti + = reinterpret_cast(fromDir->private_node); + VnodeToInode* toVti = reinterpret_cast(toDir->private_node); TRACE("volume = %p, fromDir = %llu, toDir = %llu, fromName = %s, " \ - "toName = %s", volume, fromInode->ID(), toInode->ID(), fromName, + "toName = %s", volume, fromVti->ID(), toVti->ID(), fromName, toName); - ReadLocker(fs->fRemoveNodeLock); + VnodeToInodeLocker _from(fromVti); + Inode* fromInode = fromVti->Get(); + if (fromInode == NULL) + return B_ENTRY_NOT_FOUND; + + + VnodeToInodeLocker _to(toVti); + Inode* toInode = toVti->Get(); + if (toInode == NULL) + return B_ENTRY_NOT_FOUND; ino_t id; status_t result = Inode::Rename(fromInode, toInode, fromName, toName, false, @@ -543,8 +635,14 @@ nfs4_rename(fs_volume* volume, fs_vnode* fromDir, const char* fromName, static status_t nfs4_access(fs_volume* volume, fs_vnode* vnode, int mode) { - Inode* inode = reinterpret_cast(vnode->private_node); - TRACE("volume = %p, vnode = %llu, mode = %d", volume, inode->ID(), mode); + VnodeToInode* vti = reinterpret_cast(vnode->private_node); + TRACE("volume = %p, vnode = %llu, mode = %d", volume, vti->ID(), mode); + + VnodeToInodeLocker _(vti); + Inode* inode = vti->Get(); + if (inode == NULL) + return B_ENTRY_NOT_FOUND; + return inode->Access(mode); } @@ -552,8 +650,14 @@ nfs4_access(fs_volume* volume, fs_vnode* vnode, int mode) static status_t nfs4_read_stat(fs_volume* volume, fs_vnode* vnode, struct stat* stat) { - Inode* inode = reinterpret_cast(vnode->private_node); - TRACE("volume = %p, vnode = %llu", volume, inode->ID()); + VnodeToInode* vti = reinterpret_cast(vnode->private_node); + TRACE("volume = %p, vnode = %llu", volume, vti->ID()); + + VnodeToInodeLocker _(vti); + Inode* inode = vti->Get(); + if (inode == NULL) + return B_ENTRY_NOT_FOUND; + return inode->Stat(stat); } @@ -562,13 +666,66 @@ static status_t nfs4_write_stat(fs_volume* volume, fs_vnode* vnode, const struct stat* stat, uint32 statMask) { - Inode* inode = reinterpret_cast(vnode->private_node); - TRACE("volume = %p, vnode = %llu, statMask = %lu", volume, inode->ID(), + VnodeToInode* vti = reinterpret_cast(vnode->private_node); + TRACE("volume = %p, vnode = %llu, statMask = %lu", volume, vti->ID(), statMask); + + VnodeToInodeLocker _(vti); + Inode* inode = vti->Get(); + if (inode == NULL) + return B_ENTRY_NOT_FOUND; + return inode->WriteStat(stat, statMask); } +static status_t +get_new_vnode(fs_volume* volume, ino_t id, VnodeToInode** _vti) +{ + FileSystem* fs = reinterpret_cast(volume->private_volume); + Inode* inode; + VnodeToInode* vti; + + status_t result = get_vnode(volume, id, reinterpret_cast(_vti)); + if (result == B_OK) { + vti = *_vti; + + // FIXME: race condition vti->Get() == NULL and vti->Replace(inode) + if (vti->Get() == NULL) { + result = fs->GetInode(id, &inode); + if (result != B_OK) + return result; + + vti->Replace(inode); + unremove_vnode(volume, id); + } + + return B_OK; + } + + vti = new VnodeToInode(id, fs); + if (vti == NULL) + return B_NO_MEMORY; + *_vti = vti; + + result = fs->GetInode(id, &inode); + if (result != B_OK) { + delete vti; + return result; + } + + vti->Replace(inode); + + result = new_vnode(volume, id, vti, &gNFSv4VnodeOps); + if (result != B_OK) { + delete vti; + delete inode; + } + + return B_OK; +} + + static status_t nfs4_create(fs_volume* volume, fs_vnode* dir, const char* name, int openMode, int perms, void** _cookie, ino_t* _newVnodeID) @@ -578,13 +735,14 @@ nfs4_create(fs_volume* volume, fs_vnode* dir, const char* name, int openMode, return B_NO_MEMORY; *_cookie = cookie; - Inode* inode = reinterpret_cast(dir->private_node); - FileSystem* fs = reinterpret_cast(volume->private_volume); - + VnodeToInode* vti = reinterpret_cast(dir->private_node); TRACE("volume = %p, dir = %llu, name = %s, openMode = %d, perms = %d", - volume, inode->ID(), name, openMode, perms); + volume, vti->ID(), name, openMode, perms); - ReadLocker(fs->fRemoveNodeLock); + VnodeToInodeLocker _(vti); + Inode* inode = vti->Get(); + if (inode == NULL) + return B_ENTRY_NOT_FOUND; OpenDelegationData data; status_t result = inode->Create(name, openMode, perms, cookie, &data, @@ -594,23 +752,18 @@ nfs4_create(fs_volume* volume, fs_vnode* dir, const char* name, int openMode, return result; } - Inode* child; - result = get_vnode(volume, *_newVnodeID, reinterpret_cast(&child)); + result = get_new_vnode(volume, *_newVnodeID, &vti); if (result != B_OK) { - result = inode->GetFileSystem()->GetInode(*_newVnodeID, &child); - if (result != B_OK) { - delete cookie; - return result; - } + delete cookie; + return result; + } - result = new_vnode(volume, *_newVnodeID, child, &gNFSv4VnodeOps); - if (result != B_OK) { - delete child; - delete cookie; - return result; - } - } else - unremove_vnode(volume, *_newVnodeID); + VnodeToInodeLocker _child(vti); + Inode* child = vti->Get(); + if (child == NULL) { + delete cookie; + return B_ENTRY_NOT_FOUND; + } child->SetOpenState(cookie->fOpenState); @@ -626,7 +779,6 @@ nfs4_create(fs_volume* volume, fs_vnode* dir, const char* name, int openMode, } TRACE("*cookie = %p, *newVnodeID = %llu", *_cookie, *_newVnodeID); - return result; } @@ -634,11 +786,15 @@ nfs4_create(fs_volume* volume, fs_vnode* dir, const char* name, int openMode, static status_t nfs4_open(fs_volume* volume, fs_vnode* vnode, int openMode, void** _cookie) { - Inode* inode = reinterpret_cast(vnode->private_node); - - TRACE("volume = %p, vnode = %llu, openMode = %d", volume, inode->ID(), + VnodeToInode* vti = reinterpret_cast(vnode->private_node); + TRACE("volume = %p, vnode = %llu, openMode = %d", volume, vti->ID(), openMode); + VnodeToInodeLocker _(vti); + Inode* inode = vti->Get(); + if (inode == NULL) + return B_ENTRY_NOT_FOUND; + if (inode->Type() == S_IFDIR || inode->Type() == S_IFLNK) { *_cookie = NULL; return B_OK; @@ -662,11 +818,17 @@ nfs4_open(fs_volume* volume, fs_vnode* vnode, int openMode, void** _cookie) static status_t nfs4_close(fs_volume* volume, fs_vnode* vnode, void* _cookie) { - Inode* inode = reinterpret_cast(vnode->private_node); + VnodeToInode* vti = reinterpret_cast(vnode->private_node); - TRACE("volume = %p, vnode = %llu, cookie = %p", volume, inode->ID(), + TRACE("volume = %p, vnode = %llu, cookie = %p", volume, vti->ID(), _cookie); + VnodeToInodeLocker _(vti); + Inode* inode = vti->Get(); + if (inode == NULL) + return B_ENTRY_NOT_FOUND; + + if (inode->Type() == S_IFDIR || inode->Type() == S_IFLNK) return B_OK; @@ -678,11 +840,16 @@ nfs4_close(fs_volume* volume, fs_vnode* vnode, void* _cookie) static status_t nfs4_free_cookie(fs_volume* volume, fs_vnode* vnode, void* _cookie) { - Inode* inode = reinterpret_cast(vnode->private_node); + VnodeToInode* vti = reinterpret_cast(vnode->private_node); - TRACE("volume = %p, vnode = %llu, cookie = %p", volume, inode->ID(), + TRACE("volume = %p, vnode = %llu, cookie = %p", volume, vti->ID(), _cookie); + VnodeToInodeLocker _(vti); + Inode* inode = vti->Get(); + if (inode == NULL) + return B_ENTRY_NOT_FOUND; + if (inode->Type() == S_IFDIR || inode->Type() == S_IFLNK) return B_OK; @@ -699,10 +866,14 @@ static status_t nfs4_read(fs_volume* volume, fs_vnode* vnode, void* _cookie, off_t pos, void* buffer, size_t* length) { - Inode* inode = reinterpret_cast(vnode->private_node); - + VnodeToInode* vti = reinterpret_cast(vnode->private_node); TRACE("volume = %p, vnode = %llu, cookie = %p, pos = %llu, length = %lu", - volume, inode->ID(), _cookie, pos, *length); + volume, vti->ID(), _cookie, pos, *length); + + VnodeToInodeLocker _(vti); + Inode* inode = vti->Get(); + if (inode == NULL) + return B_ENTRY_NOT_FOUND; if (inode->Type() == S_IFDIR) return B_IS_A_DIRECTORY; @@ -712,7 +883,7 @@ nfs4_read(fs_volume* volume, fs_vnode* vnode, void* _cookie, off_t pos, OpenFileCookie* cookie = reinterpret_cast(_cookie); - return inode->Read(cookie, pos, buffer, length); + return inode->Read(cookie, pos, buffer, length);; } @@ -720,10 +891,14 @@ 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(vnode->private_node); - + VnodeToInode* vti = reinterpret_cast(vnode->private_node); TRACE("volume = %p, vnode = %llu, cookie = %p, pos = %llu, length = %lu", - volume, inode->ID(), _cookie, pos, *length); + volume, vti->ID(), _cookie, pos, *length); + + VnodeToInodeLocker _(vti); + Inode* inode = vti->Get(); + if (inode == NULL) + return B_ENTRY_NOT_FOUND; if (inode->Type() == S_IFDIR) return B_IS_A_DIRECTORY; @@ -741,20 +916,36 @@ static status_t nfs4_create_dir(fs_volume* volume, fs_vnode* parent, const char* name, int mode) { - Inode* inode = reinterpret_cast(parent->private_node); - TRACE("volume = %p, parent = %llu, mode = %d", volume, inode->ID(), mode); - return inode->CreateDir(name, mode); + VnodeToInode* vti = reinterpret_cast(parent->private_node); + TRACE("volume = %p, parent = %llu, mode = %d", volume, vti->ID(), mode); + + VnodeToInodeLocker _(vti); + Inode* inode = vti->Get(); + if (inode == NULL) + return B_ENTRY_NOT_FOUND; + + ino_t id; + status_t result = inode->CreateDir(name, mode, &id); + if (result != B_OK) + return result; + + result = get_vnode(volume, id, reinterpret_cast(&vti)); + if (result == B_OK) + vti->Clear(); + return B_OK; } static status_t nfs4_remove_dir(fs_volume* volume, fs_vnode* parent, const char* name) { - Inode* inode = reinterpret_cast(parent->private_node); - FileSystem* fs = reinterpret_cast(volume->private_volume); + VnodeToInode* vti = reinterpret_cast(parent->private_node); + TRACE("volume = %p, parent = %llu, name = %s", volume, vti->ID(), name); - TRACE("volume = %p, parent = %llu, name = %s", volume, inode->ID(), name); - WriteLocker(fs->fRemoveNodeLock); + VnodeToInodeLocker _(vti); + Inode* inode = vti->Get(); + if (inode == NULL) + return B_ENTRY_NOT_FOUND; ino_t id; status_t result = inode->Remove(name, NF4DIR, &id); @@ -772,8 +963,14 @@ nfs4_open_dir(fs_volume* volume, fs_vnode* vnode, void** _cookie) return B_NO_MEMORY; *_cookie = cookie; - Inode* inode = reinterpret_cast(vnode->private_node); - TRACE("volume = %p, vnode = %llu", volume, inode->ID()); + VnodeToInode* vti = reinterpret_cast(vnode->private_node); + TRACE("volume = %p, vnode = %llu", volume, vti->ID()); + + VnodeToInodeLocker _(vti); + Inode* inode = vti->Get(); + if (inode == NULL) + return B_ENTRY_NOT_FOUND; + status_t result = inode->OpenDir(cookie); if (result != B_OK) delete cookie; @@ -788,7 +985,7 @@ static status_t nfs4_close_dir(fs_volume* volume, fs_vnode* vnode, void* _cookie) { TRACE("volume = %p, vnode = %llu, cookie = %p", volume, - reinterpret_cast(vnode->private_node)->ID(), _cookie); + reinterpret_cast(vnode->private_node)->ID(), _cookie); Cookie* cookie = reinterpret_cast(_cookie); return cookie->CancelAll(); @@ -799,7 +996,7 @@ static status_t nfs4_free_dir_cookie(fs_volume* volume, fs_vnode* vnode, void* cookie) { TRACE("volume = %p, vnode = %llu, cookie = %p", volume, - reinterpret_cast(vnode->private_node)->ID(), cookie); + reinterpret_cast(vnode->private_node)->ID(), cookie); delete reinterpret_cast(cookie); return B_OK; @@ -811,11 +1008,15 @@ nfs4_read_dir(fs_volume* volume, fs_vnode* vnode, void* _cookie, struct dirent* buffer, size_t bufferSize, uint32* _num) { OpenDirCookie* cookie = reinterpret_cast(_cookie); - Inode* inode = reinterpret_cast(vnode->private_node); - - TRACE("volume = %p, vnode = %llu, cookie = %p", volume, inode->ID(), + VnodeToInode* vti = reinterpret_cast(vnode->private_node); + TRACE("volume = %p, vnode = %llu, cookie = %p", volume, vti->ID(), _cookie); + VnodeToInodeLocker _(vti); + Inode* inode = vti->Get(); + if (inode == NULL) + return B_ENTRY_NOT_FOUND; + return inode->ReadDir(buffer, bufferSize, _num, cookie); } @@ -824,7 +1025,7 @@ static status_t nfs4_rewind_dir(fs_volume* volume, fs_vnode* vnode, void* _cookie) { TRACE("volume = %p, vnode = %llu, cookie = %p", volume, - reinterpret_cast(vnode->private_node)->ID(), _cookie); + reinterpret_cast(vnode->private_node)->ID(), _cookie); OpenDirCookie* cookie = reinterpret_cast(_cookie); cookie->fSpecial = 0; @@ -843,8 +1044,14 @@ nfs4_open_attr_dir(fs_volume* volume, fs_vnode* vnode, void** _cookie) return B_NO_MEMORY; *_cookie = cookie; - Inode* inode = reinterpret_cast(vnode->private_node); - TRACE("volume = %p, vnode = %llu", volume, inode->ID()); + VnodeToInode* vti = reinterpret_cast(vnode->private_node); + TRACE("volume = %p, vnode = %llu", volume, vti->ID()); + + VnodeToInodeLocker _(vti); + Inode* inode = vti->Get(); + if (inode == NULL) + return B_ENTRY_NOT_FOUND; + status_t result = inode->OpenAttrDir(cookie); if (result != B_OK) delete cookie; @@ -886,7 +1093,12 @@ static status_t nfs4_create_attr(fs_volume* volume, fs_vnode* vnode, const char* name, uint32 type, int openMode, void** _cookie) { - Inode* inode = reinterpret_cast(vnode->private_node); + VnodeToInode* vti = reinterpret_cast(vnode->private_node); + + VnodeToInodeLocker _(vti); + Inode* inode = vti->Get(); + if (inode == NULL) + return B_ENTRY_NOT_FOUND; OpenAttrCookie* cookie = new OpenAttrCookie; if (cookie == NULL) @@ -905,7 +1117,12 @@ static status_t nfs4_open_attr(fs_volume* volume, fs_vnode* vnode, const char* name, int openMode, void** _cookie) { - Inode* inode = reinterpret_cast(vnode->private_node); + VnodeToInode* vti = reinterpret_cast(vnode->private_node); + + VnodeToInodeLocker _(vti); + Inode* inode = vti->Get(); + if (inode == NULL) + return B_ENTRY_NOT_FOUND; OpenAttrCookie* cookie = new OpenAttrCookie; if (cookie == NULL) @@ -931,7 +1148,12 @@ nfs4_close_attr(fs_volume* volume, fs_vnode* vnode, void* _cookie) static status_t nfs4_free_attr_cookie(fs_volume* volume, fs_vnode* vnode, void* _cookie) { - Inode* inode = reinterpret_cast(vnode->private_node); + VnodeToInode* vti = reinterpret_cast(vnode->private_node); + + VnodeToInodeLocker _(vti); + Inode* inode = vti->Get(); + if (inode == NULL) + return B_ENTRY_NOT_FOUND; OpenAttrCookie* cookie = reinterpret_cast(_cookie); inode->CloseAttr(cookie); @@ -945,9 +1167,15 @@ static status_t nfs4_read_attr(fs_volume* volume, fs_vnode* vnode, void* _cookie, off_t pos, void* buffer, size_t* length) { - Inode* inode = reinterpret_cast(vnode->private_node); + VnodeToInode* vti = reinterpret_cast(vnode->private_node); OpenAttrCookie* cookie = reinterpret_cast(_cookie); bool eof; + + VnodeToInodeLocker _(vti); + Inode* inode = vti->Get(); + if (inode == NULL) + return B_ENTRY_NOT_FOUND; + return inode->ReadDirect(cookie, pos, buffer, length, &eof); } @@ -956,8 +1184,14 @@ static status_t nfs4_write_attr(fs_volume* volume, fs_vnode* vnode, void* _cookie, off_t pos, const void* buffer, size_t* length) { - Inode* inode = reinterpret_cast(vnode->private_node); + VnodeToInode* vti = reinterpret_cast(vnode->private_node); OpenAttrCookie* cookie = reinterpret_cast(_cookie); + + VnodeToInodeLocker _(vti); + Inode* inode = vti->Get(); + if (inode == NULL) + return B_ENTRY_NOT_FOUND; + return inode->WriteDirect(cookie, pos, buffer, length); } @@ -966,8 +1200,14 @@ static status_t nfs4_read_attr_stat(fs_volume* volume, fs_vnode* vnode, void* _cookie, struct stat* stat) { - Inode* inode = reinterpret_cast(vnode->private_node); + VnodeToInode* vti = reinterpret_cast(vnode->private_node); OpenAttrCookie* cookie = reinterpret_cast(_cookie); + + VnodeToInodeLocker _(vti); + Inode* inode = vti->Get(); + if (inode == NULL) + return B_ENTRY_NOT_FOUND; + return inode->Stat(stat, cookie); } @@ -976,8 +1216,14 @@ static status_t nfs4_write_attr_stat(fs_volume* volume, fs_vnode* vnode, void* _cookie, const struct stat* stat, int statMask) { - Inode* inode = reinterpret_cast(vnode->private_node); + VnodeToInode* vti = reinterpret_cast(vnode->private_node); OpenAttrCookie* cookie = reinterpret_cast(_cookie); + + VnodeToInodeLocker _(vti); + Inode* inode = vti->Get(); + if (inode == NULL) + return B_ENTRY_NOT_FOUND; + return inode->WriteStat(stat, statMask, cookie); } @@ -986,8 +1232,18 @@ static status_t nfs4_rename_attr(fs_volume* volume, fs_vnode* fromVnode, const char* fromName, fs_vnode* toVnode, const char* toName) { - Inode* fromInode = reinterpret_cast(fromVnode->private_node); - Inode* toInode = reinterpret_cast(toVnode->private_node); + VnodeToInode* vti = reinterpret_cast(toVnode->private_node); + VnodeToInodeLocker to(vti); + Inode* toInode = vti->Get(); + if (toInode == NULL) + return B_ENTRY_NOT_FOUND; + + vti = reinterpret_cast(fromVnode->private_node); + VnodeToInodeLocker from(vti); + Inode* fromInode = vti->Get(); + if (fromInode == NULL) + return B_ENTRY_NOT_FOUND; + return Inode::Rename(fromInode, toInode, fromName, toName, true); } @@ -995,7 +1251,13 @@ nfs4_rename_attr(fs_volume* volume, fs_vnode* fromVnode, const char* fromName, static status_t nfs4_remove_attr(fs_volume* volume, fs_vnode* vnode, const char* name) { - Inode* inode = reinterpret_cast(vnode->private_node); + VnodeToInode* vti = reinterpret_cast(vnode->private_node); + + VnodeToInodeLocker _(vti); + Inode* inode = vti->Get(); + if (inode == NULL) + return B_ENTRY_NOT_FOUND; + return inode->Remove(name, NF4NAMEDATTR, NULL); } @@ -1004,10 +1266,16 @@ static status_t nfs4_test_lock(fs_volume* volume, fs_vnode* vnode, void* _cookie, struct flock* lock) { - Inode* inode = reinterpret_cast(vnode->private_node); + VnodeToInode* vti = reinterpret_cast(vnode->private_node); OpenFileCookie* cookie = reinterpret_cast(_cookie); TRACE("volume = %p, vnode = %llu, cookie = %p, lock = %p", volume, - inode->ID(), _cookie, lock); + vti->ID(), _cookie, lock); + + VnodeToInodeLocker _(vti); + Inode* inode = vti->Get(); + if (inode == NULL) + return B_ENTRY_NOT_FOUND; + return inode->TestLock(cookie, lock); } @@ -1016,13 +1284,18 @@ static status_t nfs4_acquire_lock(fs_volume* volume, fs_vnode* vnode, void* _cookie, const struct flock* lock, bool wait) { - Inode* inode = reinterpret_cast(vnode->private_node); + VnodeToInode* vti = reinterpret_cast(vnode->private_node); OpenFileCookie* cookie = reinterpret_cast(_cookie); TRACE("volume = %p, vnode = %llu, cookie = %p, lock = %p", volume, - inode->ID(), _cookie, lock); + vti->ID(), _cookie, lock); + + + VnodeToInodeLocker _(vti); + Inode* inode = vti->Get(); + if (inode == NULL) + return B_ENTRY_NOT_FOUND; inode->RevalidateFileCache(); - return inode->AcquireLock(cookie, lock, wait); } @@ -1031,9 +1304,14 @@ static status_t nfs4_release_lock(fs_volume* volume, fs_vnode* vnode, void* _cookie, const struct flock* lock) { - Inode* inode = reinterpret_cast(vnode->private_node); + VnodeToInode* vti = reinterpret_cast(vnode->private_node); TRACE("volume = %p, vnode = %llu, cookie = %p, lock = %p", volume, - inode->ID(), _cookie, lock); + vti->ID(), _cookie, lock); + + VnodeToInodeLocker _(vti); + Inode* inode = vti->Get(); + if (inode == NULL) + return B_ENTRY_NOT_FOUND; if (inode->Type() == S_IFDIR || inode->Type() == S_IFLNK) return B_OK; From 83444c23219eb01b3d9ea95a9c288b6e811168c6 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Mon, 3 Dec 2012 22:47:45 +0100 Subject: [PATCH 217/252] nfs4: Complete outstanding AIO requests before releasing open state --- .../kernel/file_systems/nfs4/Inode.cpp | 31 ++++++++++++++++++- src/add-ons/kernel/file_systems/nfs4/Inode.h | 16 ++++++++++ .../kernel/file_systems/nfs4/WorkQueue.cpp | 5 +++ 3 files changed, 51 insertions(+), 1 deletion(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index 1c30888247..600a15decd 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -30,11 +30,14 @@ Inode::Inode() fFileCache(NULL), fMaxFileSize(0), fOpenState(NULL), - fWriteDirty(false) + fWriteDirty(false), + fAIOWait(create_sem(1, NULL)), + fAIOCount(0) { rw_lock_init(&fDelegationLock, NULL); mutex_init(&fStateLock, NULL); mutex_init(&fFileCacheLock, NULL); + mutex_init(&fAIOLock, NULL); } @@ -139,9 +142,13 @@ Inode::~Inode() delete fCache; delete fAttrCache; + delete_sem(fAIOWait); + mutex_destroy(&fAIOLock); mutex_destroy(&fStateLock); mutex_destroy(&fFileCacheLock); rw_lock_destroy(&fDelegationLock); + + ASSERT(fAIOCount == 0); } @@ -944,6 +951,28 @@ Inode::SyncAndCommit(bool force) return B_OK; file_cache_sync(fFileCache); + WaitAIOComplete(); return Commit(); } + +void +Inode::BeginAIOOp() +{ + MutexLocker _(fAIOLock); + fAIOCount++; + if (fAIOCount == 1) + acquire_sem(fAIOWait); +} + + +void +Inode::EndAIOOp() +{ + MutexLocker _(fAIOLock); + ASSERT(fAIOCount > 0); + fAIOCount--; + if (fAIOCount == 0) + release_sem(fAIOWait); +} + diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h b/src/add-ons/kernel/file_systems/nfs4/Inode.h index 521e1d75d9..e72aadbc46 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -112,6 +112,10 @@ public: status_t LoadAttrDirHandle(); static inline ino_t FileIdToInoT(uint64 fileid); + + void BeginAIOOp(); + void EndAIOOp(); + inline void WaitAIOComplete(); protected: Inode(); @@ -157,9 +161,21 @@ private: mutex fStateLock; bool fWriteDirty; + + sem_id fAIOWait; + uint32 fAIOCount; + mutex fAIOLock; }; +inline void +Inode::WaitAIOComplete() +{ + acquire_sem(fAIOWait); + release_sem(fAIOWait); +} + + inline ino_t Inode::FileIdToInoT(uint64 fileid) { diff --git a/src/add-ons/kernel/file_systems/nfs4/WorkQueue.cpp b/src/add-ons/kernel/file_systems/nfs4/WorkQueue.cpp index 0e00775451..da435bfb43 100644 --- a/src/add-ons/kernel/file_systems/nfs4/WorkQueue.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/WorkQueue.cpp @@ -62,6 +62,9 @@ WorkQueue::EnqueueJob(JobType type, void* args) entry->fType = type; entry->fArguments = args; + if (type == IORequest) + reinterpret_cast(args)->fInode->BeginAIOOp(); + MutexLocker locker(fQueueLock); fQueue.InsertAfter(fQueue.Tail(), entry); locker.Unlock(); @@ -152,6 +155,7 @@ WorkQueue::JobIO(IORequestArgs* args) char* buffer = reinterpret_cast(malloc(length)); if (buffer == NULL) { notify_io_request(args->fRequest, B_NO_MEMORY); + args->fInode->EndAIOOp(); return; } @@ -188,5 +192,6 @@ WorkQueue::JobIO(IORequestArgs* args) free(buffer); notify_io_request(args->fRequest, result); + args->fInode->EndAIOOp(); } From aec9dfc921c4624711e9636fb76e0a75d839c1ee Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Tue, 4 Dec 2012 01:35:00 +0100 Subject: [PATCH 218/252] nfs4: Release vnodes when no longer used --- .../file_systems/nfs4/kernel_interface.cpp | 76 +++++++++++-------- 1 file changed, 43 insertions(+), 33 deletions(-) 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 8045a8b67f..7641ac9e70 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -533,8 +533,12 @@ nfs4_create_symlink(fs_volume* volume, fs_vnode* dir, const char* name, return result; result = get_vnode(volume, id, reinterpret_cast(&vti)); - if (result == B_OK) + if (result == B_OK) { + unremove_vnode(volume, id); vti->Clear(); + put_vnode(volume, id); + } + return B_OK; } @@ -580,14 +584,17 @@ nfs4_unlink(fs_volume* volume, fs_vnode* dir, const char* name) return result; locker.Unlock(); - void* ptr; - result = get_vnode(volume, id, &ptr); - if (result == B_OK) { - vti = reinterpret_cast(ptr); + result = acquire_vnode(volume, id); + if (result == B_OK) { + ASSERT(get_vnode(volume, id, reinterpret_cast(&vti)) == B_OK); vti->Remove(); + put_vnode(volume, id); + remove_vnode(volume, id); + + put_vnode(volume, id); } - return remove_vnode(volume, id); + return B_OK; } @@ -626,6 +633,7 @@ nfs4_rename(fs_volume* volume, fs_vnode* fromDir, const char* fromName, child->fInfo.fParent = toInode->fInfo.fHandle; child->fInfo.CreateName(toInode->fInfo.fPath, toName); + put_vnode(volume, id); } return B_OK; @@ -686,43 +694,29 @@ get_new_vnode(fs_volume* volume, ino_t id, VnodeToInode** _vti) Inode* inode; VnodeToInode* vti; - status_t result = get_vnode(volume, id, reinterpret_cast(_vti)); + status_t result = acquire_vnode(volume, id); if (result == B_OK) { + ASSERT(get_vnode(volume, id, reinterpret_cast(_vti)) == B_OK); + unremove_vnode(volume, id); + + // Release after acquire + put_vnode(volume, id); + vti = *_vti; - // FIXME: race condition vti->Get() == NULL and vti->Replace(inode) if (vti->Get() == NULL) { result = fs->GetInode(id, &inode); - if (result != B_OK) + if (result != B_OK) { + put_vnode(volume, id); return result; + } vti->Replace(inode); - unremove_vnode(volume, id); } - return B_OK; } - vti = new VnodeToInode(id, fs); - if (vti == NULL) - return B_NO_MEMORY; - *_vti = vti; - - result = fs->GetInode(id, &inode); - if (result != B_OK) { - delete vti; - return result; - } - - vti->Replace(inode); - - result = new_vnode(volume, id, vti, &gNFSv4VnodeOps); - if (result != B_OK) { - delete vti; - delete inode; - } - - return B_OK; + return get_vnode(volume, id, reinterpret_cast(_vti)); //_OK; } @@ -762,6 +756,7 @@ nfs4_create(fs_volume* volume, fs_vnode* dir, const char* name, int openMode, Inode* child = vti->Get(); if (child == NULL) { delete cookie; + put_vnode(volume, *_newVnodeID); return B_ENTRY_NOT_FOUND; } @@ -930,8 +925,12 @@ nfs4_create_dir(fs_volume* volume, fs_vnode* parent, const char* name, return result; result = get_vnode(volume, id, reinterpret_cast(&vti)); - if (result == B_OK) + if (result == B_OK) { + unremove_vnode(volume, id); vti->Clear(); + put_vnode(volume, id); + } + return B_OK; } @@ -951,7 +950,18 @@ nfs4_remove_dir(fs_volume* volume, fs_vnode* parent, const char* name) status_t result = inode->Remove(name, NF4DIR, &id); if (result != B_OK) return result; - return remove_vnode(volume, id); + + result = acquire_vnode(volume, id); + if (result == B_OK) { + ASSERT(get_vnode(volume, id, reinterpret_cast(&vti)) == B_OK); + vti->Remove(); + put_vnode(volume, id); + remove_vnode(volume, id); + + put_vnode(volume, id); + } + + return B_OK; } From eed5b716d0d47b766659295406c54f910dc1a092 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Wed, 19 Dec 2012 08:12:39 +0100 Subject: [PATCH 219/252] nfs4: Fix problems with reading directory entries * Inode::ReadDir missed an entry when given buffer was too small * Each OpenDirCookie now has its own copy of directory snapshot what would prevent Inode::ReadDir from accessing freed memory when removing files and reading directory entries simultaneously * Several minor issues fixed --- .../file_systems/nfs4/DirectoryCache.cpp | 28 +++++++++++++++++++ .../kernel/file_systems/nfs4/DirectoryCache.h | 11 +++++--- .../kernel/file_systems/nfs4/Inode.cpp | 4 +-- .../kernel/file_systems/nfs4/InodeDir.cpp | 16 ++++++----- .../kernel/file_systems/nfs4/InodeRegular.cpp | 2 +- .../file_systems/nfs4/ReplyInterpreter.cpp | 5 +--- .../file_systems/nfs4/kernel_interface.cpp | 3 ++ 7 files changed, 51 insertions(+), 18 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.cpp b/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.cpp index 8585f8163d..923ae53e75 100644 --- a/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.cpp @@ -25,6 +25,14 @@ NameCacheEntry::NameCacheEntry(const char* name, ino_t node) } +NameCacheEntry::NameCacheEntry(const NameCacheEntry& entry) + : + fNode(entry.fNode), + fName(strdup(entry.fName)) +{ +} + + NameCacheEntry::~NameCacheEntry() { free(const_cast(fName)); @@ -37,6 +45,26 @@ DirectoryCacheSnapshot::DirectoryCacheSnapshot() } +DirectoryCacheSnapshot::DirectoryCacheSnapshot( + const DirectoryCacheSnapshot& snapshot) +{ + mutex_init(&fLock, NULL); + + MutexLocker _(snapshot.fLock); + NameCacheEntry* entry = snapshot.fEntries.Head(); + NameCacheEntry* new_entry; + while (entry) { + new_entry = new NameCacheEntry(*entry); + if (new_entry == NULL) + break; + + fEntries.Add(new_entry); + + entry = snapshot.fEntries.GetNext(entry); + } +} + + DirectoryCacheSnapshot::~DirectoryCacheSnapshot() { while (!fEntries.IsEmpty()) { diff --git a/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.h b/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.h index 45b7bf3133..5cc68545e4 100644 --- a/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.h +++ b/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.h @@ -24,15 +24,18 @@ struct NameCacheEntry : const char* fName; NameCacheEntry(const char* name, ino_t node); + NameCacheEntry(const NameCacheEntry& entry); ~NameCacheEntry(); }; struct DirectoryCacheSnapshot : public KernelReferenceable { - SinglyLinkedList fEntries; - mutex fLock; + SinglyLinkedList fEntries; + mutable mutex fLock; - DirectoryCacheSnapshot(); - ~DirectoryCacheSnapshot(); + DirectoryCacheSnapshot(); + DirectoryCacheSnapshot( + const DirectoryCacheSnapshot& snapshot); + ~DirectoryCacheSnapshot(); }; class DirectoryCache : public DoublyLinkedListLinkImpl { diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index 600a15decd..be79b53f70 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -250,7 +250,7 @@ Inode::Link(Inode* dir, const char* name) && dir->fCache->ChangeInfo() == changeInfo.fBefore) { dir->fCache->AddEntry(name, fInfo.fFileId, true); dir->fCache->SetChangeInfo(changeInfo.fAfter); - } else if (dir->fCache->ChangeInfo() != changeInfo.fBefore) + } else dir->fCache->Trash(); } dir->fCache->Unlock(); @@ -428,7 +428,7 @@ Inode::CreateObject(const char* name, const char* path, int mode, FileType type, if (changeInfo.fAtomic && fCache->ChangeInfo() == changeInfo.fBefore) { fCache->AddEntry(name, fileID, true); fCache->SetChangeInfo(changeInfo.fAfter); - } else if (fCache->ChangeInfo() != changeInfo.fBefore) + } else fCache->Trash(); } fCache->Unlock(); diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp b/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp index 508b5c8c22..2b71dce1e3 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp @@ -123,7 +123,7 @@ Inode::FillDirEntry(struct dirent* de, ino_t id, const char* name, uint32 pos, ASSERT(de != NULL); ASSERT(name != NULL); - uint32 nameSize = strlen(name); + uint32 nameSize = strlen(name) + 1; const uint32 entSize = sizeof(struct dirent); if (pos + entSize + nameSize > size) @@ -282,7 +282,7 @@ Inode::GetDirSnapshot(DirectoryCacheSnapshot** _snapshot, free(const_cast(name)); if (entry == NULL || entry->fName == NULL) { - if (entry->fName == NULL) + if (entry != NULL) delete entry; delete snapshot; delete[] dirents; @@ -324,10 +324,10 @@ Inode::ReadDir(void* _buffer, uint32 size, uint32* _count, else fFileSystem->Revalidator().RemoveDirectory(cache); - cookie->fSnapshot = cache->GetSnapshot(); - if (cookie->fSnapshot == NULL) { + DirectoryCacheSnapshot* snapshot = cache->GetSnapshot(); + if (snapshot == NULL) { uint64 change; - result = GetDirSnapshot(&cookie->fSnapshot, cookie, &change, + result = GetDirSnapshot(&snapshot, cookie, &change, cookie->fAttrDir); if (result != B_OK) { cache->Unlock(); @@ -335,9 +335,9 @@ Inode::ReadDir(void* _buffer, uint32 size, uint32* _count, return result; } cache->ValidateChangeInfo(change); - cache->SetSnapshot(cookie->fSnapshot); + cache->SetSnapshot(snapshot); } - cookie->fSnapshot->AcquireReference(); + cookie->fSnapshot = new DirectoryCacheSnapshot(*snapshot); fFileSystem->Revalidator().AddDirectory(cache); cache->Unlock(); fFileSystem->Revalidator().Unlock(); @@ -387,6 +387,7 @@ Inode::ReadDir(void* _buffer, uint32 size, uint32* _count, MutexLocker _(cookie->fSnapshot->fLock); for (; !overflow && i < *_count; i++) { struct dirent* de = reinterpret_cast(buffer + pos); + NameCacheEntry* temp = cookie->fCurrent; if (cookie->fCurrent == NULL) cookie->fCurrent = cookie->fSnapshot->fEntries.Head(); @@ -402,6 +403,7 @@ Inode::ReadDir(void* _buffer, uint32 size, uint32* _count, if (FillDirEntry(de, cookie->fCurrent->fNode, cookie->fCurrent->fName, pos, size) == B_BUFFER_OVERFLOW) { + cookie->fCurrent = temp; overflow = true; break; } diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp index d5fa76d8d4..7533b86408 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp @@ -52,7 +52,7 @@ Inode::CreateState(const char* name, int mode, int perms, OpenState* state, && fCache->ChangeInfo() == changeInfo.fBefore) { fCache->AddEntry(name, fileID, true); fCache->SetChangeInfo(changeInfo.fAfter); - } else if (fCache->ChangeInfo() != changeInfo.fBefore) + } else fCache->Trash(); } fCache->Unlock(); diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp index 14b8df860a..271cabb490 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp @@ -421,10 +421,7 @@ ReplyInterpreter::ReadDir(uint64* cookie, uint64* cookieVerf, isNext = fReply->Stream().GetBoolean(); } - if (!isNext) - *eof = fReply->Stream().GetBoolean(); - else - *eof = false; + *eof = fReply->Stream().GetBoolean(); *_count = count; *dirents = entries; 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 7641ac9e70..546aa0219a 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -1039,6 +1039,9 @@ nfs4_rewind_dir(fs_volume* volume, fs_vnode* vnode, void* _cookie) OpenDirCookie* cookie = reinterpret_cast(_cookie); cookie->fSpecial = 0; + if (cookie->fSnapshot != NULL) + cookie->fSnapshot->ReleaseReference(); + cookie->fSnapshot = NULL; cookie->fCurrent = NULL; cookie->fEOF = false; From aa5a8cb346abcd13bd7c401f2e82153b661235e3 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Mon, 24 Dec 2012 20:27:07 +0100 Subject: [PATCH 220/252] nfs4: Add assertions for unexpected error codes There are some NFS4 error codes we should not get if the client is operating correctly. CLID_INUSE may be caused only by incorrectly generated SETCLIENTID request. NOFILEHANDLE, RESTOREFH and OP_ILLEGAL indicate that the client has sent an incorrectly build request. BAD_STATEID and BAD_SEQID indicate a bug in handling {open,lock}_owners. LOCK_HELD happens when the client incorrectly cleans up after accessing a file. --- src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp index c4949a4511..f13d34eb39 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp @@ -20,6 +20,15 @@ NFS4Object::HandleErrors(uint32 nfs4Error, RPC::Server* serv, { uint32 leaseTime; + // No request send by the client should cause any of the following errors. + ASSERT(nfs4Error != NFS4ERR_CLID_INUSE); + ASSERT(nfs4Error != NFS4ERR_NOFILEHANDLE); + ASSERT(nfs4Error != NFS4ERR_BAD_STATEID); + ASSERT(nfs4Error != NFS4ERR_BAD_SEQID); + ASSERT(nfs4Error != NFS4ERR_RESTOREFH); + ASSERT(nfs4Error != NFS4ERR_LOCK_HELD); + ASSERT(nfs4Error != NFS4ERR_OP_ILLEGAL); + if (cookie != NULL) state = cookie->fOpenState; From fee08ed6ad16a266c5dbfc70af16d17f18c6ff5d Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Wed, 2 Jan 2013 16:20:06 +0100 Subject: [PATCH 221/252] nfs4: Fix typo: NFS4ERR_LOCKS_HELD instead of NFS4ERR_LOCK_HELD --- src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp index f13d34eb39..c213ab9bd9 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp @@ -26,7 +26,7 @@ NFS4Object::HandleErrors(uint32 nfs4Error, RPC::Server* serv, ASSERT(nfs4Error != NFS4ERR_BAD_STATEID); ASSERT(nfs4Error != NFS4ERR_BAD_SEQID); ASSERT(nfs4Error != NFS4ERR_RESTOREFH); - ASSERT(nfs4Error != NFS4ERR_LOCK_HELD); + ASSERT(nfs4Error != NFS4ERR_LOCKS_HELD); ASSERT(nfs4Error != NFS4ERR_OP_ILLEGAL); if (cookie != NULL) From 68e64c7ab03104b2464814ec3ddcf57f008eabac Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Wed, 2 Jan 2013 16:26:57 +0100 Subject: [PATCH 222/252] nfs4: Expect file system root path to be NULL --- src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp b/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp index 66bb163f33..caf4037ac0 100644 --- a/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp @@ -60,17 +60,19 @@ FileSystem::~FileSystem() static const char* GetPath(const char* root, const char* path) { - ASSERT(root != NULL); ASSERT(path != NULL); int slash = 0; int i; for (i = 0; path[i] != '\0'; i++) { - if (path[i] != root[i] || root[i] == '\0') - break; - if (path[i] == '/') slash = i; + + if (root == NULL) + break; + + if (path[i] != root[i] || root[i] == '\0') + break; } if (path[i] == '\0') From 8837efd0253fd668a6879552977ced39d7eb7a15 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Wed, 2 Jan 2013 16:40:23 +0100 Subject: [PATCH 223/252] nfs4: FileSystem may be destroyed before setting RPCServer private data --- src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp b/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp index caf4037ac0..fd5e57b3b5 100644 --- a/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp @@ -46,7 +46,9 @@ FileSystem::FileSystem(const MountConfiguration& configuration) FileSystem::~FileSystem() { - NFSServer()->RemoveFileSystem(this); + NFS4Server* server = reinterpret_cast(fServer->PrivateData()); + if (server != NULL) + server->RemoveFileSystem(this); mutex_destroy(&fDelegationLock); mutex_destroy(&fOpenLock); From 47e68f1c7a5b558ed3b5df3a5db540b91bc5140a Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Wed, 2 Jan 2013 20:17:57 +0100 Subject: [PATCH 224/252] nfs4: Avoid conflicts between threads attempting to repair TCP connection --- .../kernel/file_systems/nfs4/RPCServer.cpp | 16 +++++++++++++++- src/add-ons/kernel/file_systems/nfs4/RPCServer.h | 3 +++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp b/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp index a8ae352370..7ce3145117 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp @@ -81,12 +81,14 @@ Server::Server(Connection* connection, PeerAddress* address) fAddress(address), fPrivateData(NULL), fCallback(NULL), + fRepairCount(0), fXID(rand() << 1) { ASSERT(connection != NULL); ASSERT(address != NULL); mutex_init(&fCallbackLock, NULL); + mutex_init(&fRepairLock, NULL); _StartListening(); } @@ -98,6 +100,7 @@ Server::~Server() gRPCCallbackServer->UnregisterCallback(fCallback); delete fCallback; mutex_destroy(&fCallbackLock); + mutex_destroy(&fRepairLock); delete fPrivateData; @@ -229,6 +232,12 @@ Server::WakeCall(Request* request) status_t Server::Repair() { + uint32 thisRepair = fRepairCount; + + MutexLocker _(fRepairLock); + if (fRepairCount == thisRepair) + return B_OK; + fThreadCancel = true; status_t result = fConnection->Reconnect(); @@ -236,7 +245,12 @@ Server::Repair() return result; wait_for_thread(fThread, &result); - return _StartListening(); + result = _StartListening(); + + if (result == B_OK) + fRepairCount++; + + return result; } diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCServer.h b/src/add-ons/kernel/file_systems/nfs4/RPCServer.h index 5ba84ec5c8..8a6369b4f9 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RPCServer.h +++ b/src/add-ons/kernel/file_systems/nfs4/RPCServer.h @@ -103,6 +103,9 @@ private: mutex fCallbackLock; Callback* fCallback; + uint32 fRepairCount; + mutex fRepairLock; + vint32 fXID; static const bigtime_t kWaitTime = 1000000; }; From 345a659337ba627af5d67f2064ce7a2746c28f0c Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Wed, 2 Jan 2013 20:18:32 +0100 Subject: [PATCH 225/252] nfs4: Do not create new Inode object when deleting a vnode --- src/add-ons/kernel/file_systems/nfs4/VnodeToInode.h | 12 ++++++++++-- .../kernel/file_systems/nfs4/kernel_interface.cpp | 4 ++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/VnodeToInode.h b/src/add-ons/kernel/file_systems/nfs4/VnodeToInode.h index f0a39e78e0..e01db01b3f 100644 --- a/src/add-ons/kernel/file_systems/nfs4/VnodeToInode.h +++ b/src/add-ons/kernel/file_systems/nfs4/VnodeToInode.h @@ -23,13 +23,14 @@ public: inline void Lock(); inline void Unlock(); + inline Inode* GetPointer() const; Inode* Get(); void Replace(Inode* newInode); inline void Remove(); inline void Clear(); - inline ino_t ID(); + inline ino_t ID() const; private: ino_t fID; rw_lock fLock; @@ -105,8 +106,15 @@ VnodeToInode::Clear() } +inline Inode* +VnodeToInode::GetPointer() const +{ + return fInode; +} + + inline ino_t -VnodeToInode::ID() +VnodeToInode::ID() const { return fID; } 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 546aa0219a..2933d2af7a 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -339,10 +339,10 @@ nfs4_remove_vnode(fs_volume* volume, fs_vnode* vnode, bool reenter) VnodeToInode* vti = reinterpret_cast(vnode->private_node); TRACE("volume = %p, vnode = %llu", volume, vti->ID()); - if (fs->Root() == vti->Get()) + if (fs->Root() == vti->GetPointer()) return B_OK; - ASSERT(vti->Get() == NULL); + ASSERT(vti->GetPointer() == NULL); delete vti; return B_OK; From 6136b82b1e04cc9c016268154502584fd01f8a7d Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Thu, 3 Jan 2013 01:50:22 +0100 Subject: [PATCH 226/252] nfs4: Fix handling of retried CLOSE requests --- src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp | 7 ++++++- src/add-ons/kernel/file_systems/nfs4/OpenState.cpp | 8 ++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp index c213ab9bd9..69381930f9 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Object.cpp @@ -24,7 +24,6 @@ NFS4Object::HandleErrors(uint32 nfs4Error, RPC::Server* serv, ASSERT(nfs4Error != NFS4ERR_CLID_INUSE); ASSERT(nfs4Error != NFS4ERR_NOFILEHANDLE); ASSERT(nfs4Error != NFS4ERR_BAD_STATEID); - ASSERT(nfs4Error != NFS4ERR_BAD_SEQID); ASSERT(nfs4Error != NFS4ERR_RESTOREFH); ASSERT(nfs4Error != NFS4ERR_LOCKS_HELD); ASSERT(nfs4Error != NFS4ERR_OP_ILLEGAL); @@ -36,6 +35,12 @@ NFS4Object::HandleErrors(uint32 nfs4Error, RPC::Server* serv, case NFS4_OK: return false; + // retransmission of CLOSE caused seqid to fall back + case NFS4ERR_BAD_SEQID: + ASSERT(sequence != NULL); + (*sequence)++; + return true; + // server needs more time, we need to wait case NFS4ERR_LOCKED: case NFS4ERR_DELAY: diff --git a/src/add-ons/kernel/file_systems/nfs4/OpenState.cpp b/src/add-ons/kernel/file_systems/nfs4/OpenState.cpp index f83d656fab..446503de6a 100644 --- a/src/add-ons/kernel/file_systems/nfs4/OpenState.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/OpenState.cpp @@ -290,6 +290,14 @@ OpenState::Close() sequence += IncrementSequence(reply.NFS4Error()); + // RFC 3530 8.10.1. Some servers does not do anything to help client + // recognize retried CLOSE requests so we just assume that BAD_STATEID + // on CLOSE request is just a result of retransmission. + if (reply.NFS4Error() == NFS4ERR_BAD_STATEID) { + fFileSystem->OpenOwnerSequenceUnlock(sequence); + return B_OK; + } + if (HandleErrors(reply.NFS4Error(), serv, NULL, this, &sequence)) continue; fFileSystem->OpenOwnerSequenceUnlock(sequence); From e8ef557a560f15c0133390e86288d17c2ad41114 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Thu, 3 Jan 2013 01:56:47 +0100 Subject: [PATCH 227/252] nfs4: Fix double delete rpc when WaitCall fails --- src/add-ons/kernel/file_systems/nfs4/Request.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Request.cpp b/src/add-ons/kernel/file_systems/nfs4/Request.cpp index 3924f3bc03..b4c4e43c24 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Request.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Request.cpp @@ -125,6 +125,9 @@ Request::_SendTCP(Cookie* cookie) } } while (result != B_OK && (hard || attempts++ < retryLimit)); + if (result != B_OK) + return result; + if (cookie != NULL) cookie->UnregisterRequest(rpc); @@ -133,11 +136,11 @@ Request::_SendTCP(Cookie* cookie) result = rpc->fError; delete rpc; return result; - } else { - fReply.SetTo(rpl); - delete rpc; - return B_OK; - }; + } + + fReply.SetTo(rpl); + delete rpc; + return B_OK; } From d72bdcc88a354b1fc118d05b204649843a4a6cbf Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Thu, 3 Jan 2013 15:37:36 +0100 Subject: [PATCH 228/252] nfs4: Do not remove RootInode too soon --- .../kernel/file_systems/nfs4/VnodeToInode.cpp | 5 +++-- .../kernel/file_systems/nfs4/VnodeToInode.h | 15 +++++++++++++-- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/VnodeToInode.cpp b/src/add-ons/kernel/file_systems/nfs4/VnodeToInode.cpp index 42b3461058..b77feae8f4 100644 --- a/src/add-ons/kernel/file_systems/nfs4/VnodeToInode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/VnodeToInode.cpp @@ -27,9 +27,10 @@ void VnodeToInode::Replace(Inode* newInode) { WriteLocker _(fLock); - if (fInode != NULL) + if (fInode != NULL && !IsRoot()) { fInode->GetFileSystem()->InoIdMap()->MarkRemoved(fID); - delete fInode; + delete fInode; + } fInode = newInode; if (fInode != NULL) { diff --git a/src/add-ons/kernel/file_systems/nfs4/VnodeToInode.h b/src/add-ons/kernel/file_systems/nfs4/VnodeToInode.h index e01db01b3f..302457a721 100644 --- a/src/add-ons/kernel/file_systems/nfs4/VnodeToInode.h +++ b/src/add-ons/kernel/file_systems/nfs4/VnodeToInode.h @@ -14,6 +14,7 @@ #include "Inode.h" #include "InodeIdMap.h" +#include "RootInode.h" class VnodeToInode { public: @@ -31,6 +32,8 @@ public: inline void Clear(); inline ino_t ID() const; + + inline bool IsRoot() const; private: ino_t fID; rw_lock fLock; @@ -70,7 +73,7 @@ inline VnodeToInode::~VnodeToInode() { Remove(); - if (fFileSystem != NULL) + if (fFileSystem != NULL && !IsRoot()) fFileSystem->InoIdMap()->RemoveEntry(fID); rw_lock_destroy(&fLock); } @@ -101,11 +104,19 @@ inline void VnodeToInode::Clear() { WriteLocker _(fLock); - delete fInode; + if (!IsRoot()) + delete fInode; fInode = NULL; } +inline bool +VnodeToInode::IsRoot() const +{ + return fInode && fFileSystem && fInode->ID() == fFileSystem->Root()->ID(); +} + + inline Inode* VnodeToInode::GetPointer() const { From 332621d196b32ed04abf0e317ca0870d278a6c1c Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Fri, 4 Jan 2013 16:03:36 +0100 Subject: [PATCH 229/252] nfs4: Use DoublyLinkedList instead of custom FileSystem list implementation --- .../kernel/file_systems/nfs4/FileSystem.cpp | 2 -- .../kernel/file_systems/nfs4/FileSystem.h | 4 +-- .../kernel/file_systems/nfs4/NFS4Server.cpp | 36 +++++++------------ .../kernel/file_systems/nfs4/NFS4Server.h | 2 +- 4 files changed, 15 insertions(+), 29 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp b/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp index fd5e57b3b5..1b6031c8a9 100644 --- a/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp @@ -24,8 +24,6 @@ extern RPC::ProgramData* CreateNFS4Server(RPC::Server* serv); FileSystem::FileSystem(const MountConfiguration& configuration) : - fNext(NULL), - fPrev(NULL), fOpenCount(0), fOpenOwnerSequence(0), fNamedAttrs(true), diff --git a/src/add-ons/kernel/file_systems/nfs4/FileSystem.h b/src/add-ons/kernel/file_systems/nfs4/FileSystem.h index 2937066e41..d1f0c8b343 100644 --- a/src/add-ons/kernel/file_systems/nfs4/FileSystem.h +++ b/src/add-ons/kernel/file_systems/nfs4/FileSystem.h @@ -27,7 +27,7 @@ struct MountConfiguration { bool fCacheMetadata; }; -class FileSystem { +class FileSystem : public DoublyLinkedListLinkImpl { public: static status_t Mount(FileSystem** pfs, RPC::Server* serv, const char* path, dev_t id, @@ -76,8 +76,6 @@ public: inline const MountConfiguration& GetConfiguration(); - FileSystem* fNext; - FileSystem* fPrev; private: FileSystem(const MountConfiguration& config); diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp index 1de3bcf463..c9b0867b2b 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp @@ -21,7 +21,6 @@ NFS4Server::NFS4Server(RPC::Server* serv) fLeaseTime(0), fClientIdLastUse(0), fUseCount(0), - fFileSystems(NULL), fServer(serv) { ASSERT(serv != NULL); @@ -58,7 +57,7 @@ NFS4Server::ServerRebooted(uint64 clientId) // reclaim all opened files and held locks from all filesystems MutexLocker _(fFSLock); - FileSystem* fs = fFileSystems; + FileSystem* fs = fFileSystems.Head(); while (fs != NULL) { DoublyLinkedList::Iterator iterator = fs->OpenFilesLock().GetIterator(); @@ -70,7 +69,7 @@ NFS4Server::ServerRebooted(uint64 clientId) } fs->OpenFilesUnlock(); - fs = fs->fNext; + fs = fFileSystems.GetNext(fs); } return fClientId; @@ -83,11 +82,8 @@ NFS4Server::AddFileSystem(FileSystem* fs) ASSERT(fs != NULL); MutexLocker _(fFSLock); - fs->fPrev = NULL; - fs->fNext = fFileSystems; - if (fFileSystems != NULL) - fFileSystems->fPrev = fs; - fFileSystems = fs; + fFileSystems.Add(fs); + fUseCount += fs->OpenFilesCount(); if (fs->OpenFilesCount() > 0) _StartRenewing(); @@ -100,13 +96,7 @@ NFS4Server::RemoveFileSystem(FileSystem* fs) ASSERT(fs != NULL); MutexLocker _(fFSLock); - if (fs == fFileSystems) - fFileSystems = fs->fNext; - - if (fs->fNext) - fs->fNext->fPrev = fs->fPrev; - if (fs->fPrev) - fs->fPrev->fNext = fs->fNext; + fFileSystems.Remove(fs); fUseCount -= fs->OpenFilesCount(); } @@ -152,10 +142,10 @@ NFS4Server::FileSystemMigrated() { // reclaim all opened files and held locks from all filesystems MutexLocker _(fFSLock); - FileSystem* fs = fFileSystems; + FileSystem* fs = fFileSystems.Head(); while (fs != NULL) { fs->Migrate(fServer); - fs = fs->fNext; + fs = fFileSystems.GetNext(fs); } return B_OK; @@ -336,13 +326,13 @@ NFS4Server::CallbackRecall(RequestInterpreter* request, ReplyBuilder* reply) MutexLocker locker(fFSLock); Delegation* delegation = NULL; - FileSystem* current = fFileSystems; + FileSystem* current = fFileSystems.Head(); while (current != NULL) { delegation = current->GetDelegation(handle); if (delegation != NULL) break; - current = current->fNext; + current = fFileSystems.GetNext(current); } locker.Unlock(); @@ -379,13 +369,13 @@ NFS4Server::CallbackGetAttr(RequestInterpreter* request, ReplyBuilder* reply) MutexLocker locker(fFSLock); Delegation* delegation = NULL; - FileSystem* current = fFileSystems; + FileSystem* current = fFileSystems.Head(); while (current != NULL) { delegation = current->GetDelegation(handle); if (delegation != NULL) break; - current = current->fNext; + current = fFileSystems.GetNext(current); } locker.Unlock(); @@ -411,7 +401,7 @@ status_t NFS4Server::RecallAll() { MutexLocker _(fFSLock); - FileSystem* fs = fFileSystems; + FileSystem* fs = fFileSystems.Head(); while (fs != NULL) { DoublyLinkedList& list = fs->DelegationsLock(); DoublyLinkedList::Iterator iterator = list.GetIterator(); @@ -427,7 +417,7 @@ NFS4Server::RecallAll() } fs->DelegationsUnlock(); - fs = fs->fNext; + fs = fFileSystems.GetNext(fs); } return B_OK; diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h index 4fe2dccb23..624b0fe26a 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h @@ -66,7 +66,7 @@ private: mutex fClientIdLock; uint32 fUseCount; - FileSystem* fFileSystems; + DoublyLinkedList fFileSystems; mutex fFSLock; RPC::Server* fServer; From 4d120407378d6ec21783c076cdbb753e81a62eba Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Fri, 4 Jan 2013 20:05:15 +0100 Subject: [PATCH 230/252] nfs4: Remove CacheRevalidator There is no point in periodically revalidating all existing directory caches. Directory snapshot can be revalidated when readdir is invoked. --- .../file_systems/nfs4/CacheRevalidator.cpp | 122 ------------------ .../file_systems/nfs4/CacheRevalidator.h | 83 ------------ src/add-ons/kernel/file_systems/nfs4/Cookie.h | 1 + .../file_systems/nfs4/DirectoryCache.cpp | 76 ++++++----- .../kernel/file_systems/nfs4/DirectoryCache.h | 16 +-- .../kernel/file_systems/nfs4/FileSystem.h | 12 -- .../kernel/file_systems/nfs4/Inode.cpp | 7 +- src/add-ons/kernel/file_systems/nfs4/Inode.h | 1 + .../kernel/file_systems/nfs4/InodeDir.cpp | 29 ++--- src/add-ons/kernel/file_systems/nfs4/Jamfile | 1 - 10 files changed, 61 insertions(+), 287 deletions(-) delete mode 100644 src/add-ons/kernel/file_systems/nfs4/CacheRevalidator.cpp delete mode 100644 src/add-ons/kernel/file_systems/nfs4/CacheRevalidator.h diff --git a/src/add-ons/kernel/file_systems/nfs4/CacheRevalidator.cpp b/src/add-ons/kernel/file_systems/nfs4/CacheRevalidator.cpp deleted file mode 100644 index 5391c1264e..0000000000 --- a/src/add-ons/kernel/file_systems/nfs4/CacheRevalidator.cpp +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright 2012 Haiku, Inc. All rights reserved. - * Distributed under the terms of the MIT License. - * - * Authors: - * Paweł Dziepak, pdziepak@quarnos.org - */ - - -#include "CacheRevalidator.h" - -#include - -#include "NFS4Defs.h" - - -CacheRevalidator::CacheRevalidator() - : - fThreadCancel(false), - fWaitCancel(create_sem(0, NULL)) -{ - mutex_init(&fDirectoryCachesLock, NULL); - - _StartRevalidator(); -} - - -CacheRevalidator::~CacheRevalidator() -{ - fThreadCancel = true; - release_sem(fWaitCancel); - status_t result; - wait_for_thread(fThread, &result); - - delete_sem(fThreadCancel); - mutex_destroy(&fDirectoryCachesLock); -} - - -status_t -CacheRevalidator::_StartRevalidator() -{ - fThreadCancel = false; - fThread = spawn_kernel_thread(&CacheRevalidator::_DirectoryRevalidatorStart, - "NFSv4 Cache Revalidator", B_NORMAL_PRIORITY, this); - if (fThread < B_OK) - return fThread; - - status_t result = resume_thread(fThread); - if (result != B_OK) { - kill_thread(fThread); - return result; - } - - return B_OK; -} - - -status_t -CacheRevalidator::_DirectoryRevalidatorStart(void* object) -{ - ASSERT(object != NULL); - - CacheRevalidator* revalidator = reinterpret_cast(object); - revalidator->_DirectoryCacheRevalidator(); - return B_OK; -} - - -void -CacheRevalidator::_DirectoryCacheRevalidator() -{ - while (!fThreadCancel) { - MutexLocker locker(fDirectoryCachesLock); - DirectoryCache* current = fDirectoryCaches.Head(); - - if (current == NULL) { - locker.Unlock(); - - status_t result = acquire_sem_etc(fWaitCancel, 1, - B_RELATIVE_TIMEOUT, DirectoryCache::kExpirationTime); - - if (result != B_TIMED_OUT) { - if (result == B_OK) - release_sem(fWaitCancel); - return; - } - continue; - } - - current->Lock(); - if (!current->Valid()) { - RemoveDirectory(current); - current->Unlock(); - continue; - } - - if (current->ExpireTime() > system_time()) { - current->Unlock(); - locker.Unlock(); - - status_t result = acquire_sem_etc(fWaitCancel, 1, - B_ABSOLUTE_TIMEOUT, current->ExpireTime()); - if (result != B_TIMED_OUT) { - if (result == B_OK) - release_sem(fWaitCancel); - return; - } - - continue; - } - - fDirectoryCaches.RemoveHead(); - current->fRevalidated = false; - - if (current->Revalidate() == B_OK) - AddDirectory(current); - - current->Unlock(); - } -} - diff --git a/src/add-ons/kernel/file_systems/nfs4/CacheRevalidator.h b/src/add-ons/kernel/file_systems/nfs4/CacheRevalidator.h deleted file mode 100644 index a4764dcdbf..0000000000 --- a/src/add-ons/kernel/file_systems/nfs4/CacheRevalidator.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright 2012 Haiku, Inc. All rights reserved. - * Distributed under the terms of the MIT License. - * - * Authors: - * Paweł Dziepak, pdziepak@quarnos.org - */ -#ifndef CACHEREVALIDATOR_H -#define CACHEREVALIDATOR_H - - -#include -#include -#include - -#include "DirectoryCache.h" - - -class CacheRevalidator { -public: - CacheRevalidator(); - ~CacheRevalidator(); - - inline void Lock(); - inline void Unlock(); - - - inline void AddDirectory(DirectoryCache* cache); - inline void RemoveDirectory(DirectoryCache* cache); - -private: - void _DirectoryCacheRevalidator(); - static status_t _DirectoryRevalidatorStart(void* object); - status_t _StartRevalidator(); - - thread_id fThread; - bool fThreadCancel; - sem_id fWaitCancel; - - DoublyLinkedList fDirectoryCaches; - mutex fDirectoryCachesLock; -}; - - -inline void -CacheRevalidator::Lock() -{ - mutex_lock(&fDirectoryCachesLock); -} - - -inline void -CacheRevalidator::Unlock() -{ - mutex_unlock(&fDirectoryCachesLock); -} - - -inline void -CacheRevalidator::AddDirectory(DirectoryCache* cache) -{ - ASSERT(cache != NULL); - - if (!cache->fRevalidated) { - cache->fRevalidated = true; - fDirectoryCaches.InsertAfter(fDirectoryCaches.Tail(), cache); - } -} - - -inline void -CacheRevalidator::RemoveDirectory(DirectoryCache* cache) -{ - ASSERT(cache != NULL); - - if (cache->fRevalidated == true) - fDirectoryCaches.Remove(cache); - cache->fRevalidated = false; -} - - -#endif // CACHEREVALIDATOR_H - diff --git a/src/add-ons/kernel/file_systems/nfs4/Cookie.h b/src/add-ons/kernel/file_systems/nfs4/Cookie.h index c8956eec58..a3d36c9c8c 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Cookie.h +++ b/src/add-ons/kernel/file_systems/nfs4/Cookie.h @@ -11,6 +11,7 @@ #include +#include "DirectoryCache.h" #include "FileSystem.h" diff --git a/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.cpp b/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.cpp index 923ae53e75..c40707a35d 100644 --- a/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.cpp @@ -92,10 +92,6 @@ DirectoryCache::DirectoryCache(Inode* inode, bool attr) DirectoryCache::~DirectoryCache() { - fInode->GetFileSystem()->Revalidator().Lock(); - fInode->GetFileSystem()->Revalidator().RemoveDirectory(this); - fInode->GetFileSystem()->Revalidator().Unlock(); - mutex_destroy(&fLock); } @@ -119,7 +115,7 @@ DirectoryCache::Trash() delete current; } - SetSnapshot(NULL); + _SetSnapshot(NULL); fTrashed = true; } @@ -207,7 +203,7 @@ DirectoryCache::RemoveEntry(const char* name) void -DirectoryCache::SetSnapshot(DirectoryCacheSnapshot* snapshot) +DirectoryCache::_SetSnapshot(DirectoryCacheSnapshot* snapshot) { if (fDirectoryCache != NULL) fDirectoryCache->ReleaseReference(); @@ -215,9 +211,48 @@ DirectoryCache::SetSnapshot(DirectoryCacheSnapshot* snapshot) } +status_t +DirectoryCache::_LoadSnapshot(bool trash) +{ + DirectoryCacheSnapshot* oldSnapshot = fDirectoryCache; + if (oldSnapshot != NULL) + oldSnapshot->AcquireReference(); + + if (trash) + Trash(); + + DirectoryCacheSnapshot* newSnapshot; + status_t result = fInode->GetDirSnapshot(&newSnapshot, NULL, &fChange, + fAttrDir); + if (result != B_OK) { + if (oldSnapshot != NULL) + oldSnapshot->ReleaseReference(); + return result; + } + newSnapshot->AcquireReference(); + + _SetSnapshot(newSnapshot); + fExpireTime = system_time() + kExpirationTime; + + fTrashed = false; + + if (oldSnapshot != NULL) + NotifyChanges(oldSnapshot, newSnapshot); + + if (oldSnapshot != NULL) + oldSnapshot->ReleaseReference(); + + newSnapshot->ReleaseReference(); + return B_OK; +} + + status_t DirectoryCache::Revalidate() { + if (fExpireTime < system_time()) + return B_OK; + uint64 change; if (fInode->GetChangeInfo(&change, fAttrDir) != B_OK) { Trash(); @@ -229,34 +264,7 @@ DirectoryCache::Revalidate() return B_OK; } - DirectoryCacheSnapshot* oldSnapshot = fDirectoryCache; - if (oldSnapshot == NULL) { - Trash(); - return B_ERROR; - } - - oldSnapshot->AcquireReference(); - - Trash(); - - DirectoryCacheSnapshot* newSnapshot; - status_t result = fInode->GetDirSnapshot(&newSnapshot, NULL, &fChange, - fAttrDir); - if (result != B_OK) { - oldSnapshot->ReleaseReference(); - return B_ERROR; - } - newSnapshot->AcquireReference(); - - SetSnapshot(newSnapshot); - fExpireTime = system_time() + kExpirationTime; - fTrashed = false; - - NotifyChanges(oldSnapshot, newSnapshot); - oldSnapshot->ReleaseReference(); - newSnapshot->ReleaseReference(); - - return B_OK; + return _LoadSnapshot(true); } diff --git a/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.h b/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.h index 5cc68545e4..7abefb7d91 100644 --- a/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.h +++ b/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.h @@ -38,7 +38,7 @@ struct DirectoryCacheSnapshot : public KernelReferenceable { ~DirectoryCacheSnapshot(); }; -class DirectoryCache : public DoublyLinkedListLinkImpl { +class DirectoryCache { public: DirectoryCache(Inode* inode, bool attr = false); ~DirectoryCache(); @@ -54,7 +54,6 @@ public: bool created = false); void RemoveEntry(const char* name); - void SetSnapshot(DirectoryCacheSnapshot* snapshot); inline DirectoryCacheSnapshot* GetSnapshot(); inline SinglyLinkedList& EntriesList(); @@ -66,7 +65,6 @@ public: inline uint64 ChangeInfo(); inline Inode* GetInode(); - inline time_t ExpireTime(); static const bigtime_t kExpirationTime = 15000000; @@ -76,6 +74,9 @@ protected: DirectoryCacheSnapshot* newSnapshot); private: + void _SetSnapshot(DirectoryCacheSnapshot* snapshot); + status_t _LoadSnapshot(bool trash); + SinglyLinkedList fNameCache; DirectoryCacheSnapshot* fDirectoryCache; @@ -115,6 +116,8 @@ DirectoryCache::Valid() inline DirectoryCacheSnapshot* DirectoryCache::GetSnapshot() { + if (fDirectoryCache == NULL) + _LoadSnapshot(false); return fDirectoryCache; } @@ -164,12 +167,5 @@ DirectoryCache::GetInode() } -inline time_t -DirectoryCache::ExpireTime() -{ - return fExpireTime; -} - - #endif // DIRECTORYCACHE_H diff --git a/src/add-ons/kernel/file_systems/nfs4/FileSystem.h b/src/add-ons/kernel/file_systems/nfs4/FileSystem.h index d1f0c8b343..67e39967d4 100644 --- a/src/add-ons/kernel/file_systems/nfs4/FileSystem.h +++ b/src/add-ons/kernel/file_systems/nfs4/FileSystem.h @@ -9,7 +9,6 @@ #define FILESYSTEM_H -#include "CacheRevalidator.h" #include "Delegation.h" #include "InodeIdMap.h" #include "NFS4Defs.h" @@ -51,8 +50,6 @@ public: void RemoveDelegation(Delegation* delegation); Delegation* GetDelegation(const FileHandle& handle); - inline CacheRevalidator& Revalidator(); - inline bool IsAttrSupported(Attribute attr) const; inline uint32 ExpireType() const; @@ -79,8 +76,6 @@ public: private: FileSystem(const MountConfiguration& config); - CacheRevalidator fCacheRevalidator; - mutex fDelegationLock; DoublyLinkedList fDelegationList; AVLTreeMap fHandleToDelegation; @@ -113,13 +108,6 @@ private: }; -inline CacheRevalidator& -FileSystem::Revalidator() -{ - return fCacheRevalidator; -} - - inline RootInode* FileSystem::Root() { diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index be79b53f70..795a2a206b 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -204,20 +204,15 @@ Inode::LookUp(const char* name, ino_t* id) if (result != B_OK) return result; - fFileSystem->Revalidator().Lock(); fCache->Lock(); if (!fCache->Valid()) { fCache->Reset(); fCache->SetChangeInfo(change); - } else { - fFileSystem->Revalidator().RemoveDirectory(fCache); + } else fCache->ValidateChangeInfo(change); - } fCache->AddEntry(name, *id); - fFileSystem->Revalidator().AddDirectory(fCache); fCache->Unlock(); - fFileSystem->Revalidator().Unlock(); 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 e72aadbc46..da4802fe8c 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -9,6 +9,7 @@ #define INODE_H +#include "DirectoryCache.h" #include "MetadataCache.h" #include "NFS4Inode.h" #include "OpenState.h" diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp b/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp index 2b71dce1e3..10d2943a6c 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp @@ -317,30 +317,21 @@ Inode::ReadDir(void* _buffer, uint32 size, uint32* _count, status_t result; DirectoryCache* cache = cookie->fAttrDir ? fAttrCache : fCache; if (cookie->fSnapshot == NULL) { - fFileSystem->Revalidator().Lock(); cache->Lock(); - if (!cache->Valid()) - cache->Reset(); - else - fFileSystem->Revalidator().RemoveDirectory(cache); + result = cache->Revalidate(); + if (result != B_OK) { + cache->Unlock(); + return result; + } DirectoryCacheSnapshot* snapshot = cache->GetSnapshot(); - if (snapshot == NULL) { - uint64 change; - result = GetDirSnapshot(&snapshot, cookie, &change, - cookie->fAttrDir); - if (result != B_OK) { - cache->Unlock(); - fFileSystem->Revalidator().Unlock(); - return result; - } - cache->ValidateChangeInfo(change); - cache->SetSnapshot(snapshot); - } + ASSERT(snapshot != NULL); + cookie->fSnapshot = new DirectoryCacheSnapshot(*snapshot); - fFileSystem->Revalidator().AddDirectory(cache); cache->Unlock(); - fFileSystem->Revalidator().Unlock(); + + if (cookie->fSnapshot == NULL) + return B_NO_MEMORY; } char* buffer = reinterpret_cast(_buffer); diff --git a/src/add-ons/kernel/file_systems/nfs4/Jamfile b/src/add-ons/kernel/file_systems/nfs4/Jamfile index c77e63402f..3d678a9001 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Jamfile +++ b/src/add-ons/kernel/file_systems/nfs4/Jamfile @@ -4,7 +4,6 @@ UsePrivateKernelHeaders ; UsePrivateHeaders shared ; KernelAddon nfs4 : - CacheRevalidator.cpp Cookie.cpp Connection.cpp Delegation.cpp From dadd844f360f3c3b1d055177106c69324024acbd Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Fri, 4 Jan 2013 22:25:21 +0100 Subject: [PATCH 231/252] nfs4: Multiple style fixes --- src/add-ons/kernel/file_systems/nfs4/Connection.cpp | 4 ++-- src/add-ons/kernel/file_systems/nfs4/FileInfo.cpp | 4 ++-- src/add-ons/kernel/file_systems/nfs4/IdMap.h | 1 + src/add-ons/kernel/file_systems/nfs4/OpenState.cpp | 2 +- src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp | 2 +- 5 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Connection.cpp b/src/add-ons/kernel/file_systems/nfs4/Connection.cpp index 7191a8d1b7..e38953a3db 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Connection.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Connection.cpp @@ -563,8 +563,8 @@ Connection::SetTo(Connection **_connection, int socket, status_t Connection::Connect() { - const sockaddr& address = - *reinterpret_cast(&fPeerAddress); + const sockaddr& address + = *reinterpret_cast(&fPeerAddress); switch (fPeerAddress.fProtocol) { case IPPROTO_TCP: diff --git a/src/add-ons/kernel/file_systems/nfs4/FileInfo.cpp b/src/add-ons/kernel/file_systems/nfs4/FileInfo.cpp index ec4b073e1b..1a1edf33d0 100644 --- a/src/add-ons/kernel/file_systems/nfs4/FileInfo.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/FileInfo.cpp @@ -59,8 +59,8 @@ FileInfo::CreateName(const char* dirPath, const char* name) return B_NO_MEMORY; if (dirPath != NULL) { - char* path = reinterpret_cast(malloc(strlen(name) + 2 + - strlen(dirPath))); + char* path = reinterpret_cast(malloc(strlen(name) + 2 + + strlen(dirPath))); if (path == NULL) return B_NO_MEMORY; diff --git a/src/add-ons/kernel/file_systems/nfs4/IdMap.h b/src/add-ons/kernel/file_systems/nfs4/IdMap.h index fd89682364..daf66446cb 100644 --- a/src/add-ons/kernel/file_systems/nfs4/IdMap.h +++ b/src/add-ons/kernel/file_systems/nfs4/IdMap.h @@ -51,6 +51,7 @@ IdMap::InitStatus() return fInitStatus; } + extern IdMap* gIdMapper; extern mutex gIdMapperLock; diff --git a/src/add-ons/kernel/file_systems/nfs4/OpenState.cpp b/src/add-ons/kernel/file_systems/nfs4/OpenState.cpp index 446503de6a..13e2d50342 100644 --- a/src/add-ons/kernel/file_systems/nfs4/OpenState.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/OpenState.cpp @@ -294,7 +294,7 @@ OpenState::Close() // recognize retried CLOSE requests so we just assume that BAD_STATEID // on CLOSE request is just a result of retransmission. if (reply.NFS4Error() == NFS4ERR_BAD_STATEID) { - fFileSystem->OpenOwnerSequenceUnlock(sequence); + fFileSystem->OpenOwnerSequenceUnlock(sequence); return B_OK; } 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 2933d2af7a..abc4607ea4 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -716,7 +716,7 @@ get_new_vnode(fs_volume* volume, ino_t id, VnodeToInode** _vti) return B_OK; } - return get_vnode(volume, id, reinterpret_cast(_vti)); //_OK; + return get_vnode(volume, id, reinterpret_cast(_vti)); } From ad1a84af93a14af86a18703657150e59da5dffdc Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Fri, 4 Jan 2013 22:39:40 +0100 Subject: [PATCH 232/252] nfs4: Make request time limit adjustable --- .../kernel/file_systems/nfs4/FileSystem.h | 9 ++++---- .../kernel/file_systems/nfs4/RPCServer.cpp | 23 ------------------- .../kernel/file_systems/nfs4/RPCServer.h | 5 +--- .../kernel/file_systems/nfs4/Request.cpp | 9 +++++--- .../file_systems/nfs4/kernel_interface.cpp | 5 ++++ 5 files changed, 17 insertions(+), 34 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/FileSystem.h b/src/add-ons/kernel/file_systems/nfs4/FileSystem.h index 67e39967d4..87fa4b9fb0 100644 --- a/src/add-ons/kernel/file_systems/nfs4/FileSystem.h +++ b/src/add-ons/kernel/file_systems/nfs4/FileSystem.h @@ -19,11 +19,12 @@ class Inode; class RootInode; struct MountConfiguration { - bool fHard; - int fRetryLimit; + bool fHard; + int fRetryLimit; + bigtime_t fRequestTimeout; - bool fEmulateNamedAttrs; - bool fCacheMetadata; + bool fEmulateNamedAttrs; + bool fCacheMetadata; }; class FileSystem : public DoublyLinkedListLinkImpl { diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp b/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp index 7ce3145117..1b7ac54de5 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp @@ -134,29 +134,6 @@ Server::_StartListening() } -status_t -Server::SendCall(Call* call, Reply** reply) -{ - ASSERT(call != NULL); - ASSERT(reply != NULL); - - Request* req; - status_t result = SendCallAsync(call, reply, &req); - if (result != B_OK) - return result; - - result = WaitCall(req); - if (result != B_OK) { - CancelCall(req); - delete req; - return result; - } - - delete req; - return B_OK; -} - - status_t Server::SendCallAsync(Call* call, Reply** reply, Request** request) { diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCServer.h b/src/add-ons/kernel/file_systems/nfs4/RPCServer.h index 8a6369b4f9..738162d92f 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RPCServer.h +++ b/src/add-ons/kernel/file_systems/nfs4/RPCServer.h @@ -60,15 +60,13 @@ public: PeerAddress* address); virtual ~Server(); - status_t SendCall(Call* call, Reply** reply); - status_t SendCallAsync(Call* call, Reply** reply, Request** request); status_t ResendCallAsync(Call* call, Request* request); inline status_t WaitCall(Request* request, - bigtime_t time = kWaitTime); + bigtime_t time); inline status_t CancelCall(Request* request); status_t WakeCall(Request* request); @@ -107,7 +105,6 @@ private: mutex fRepairLock; vint32 fXID; - static const bigtime_t kWaitTime = 1000000; }; diff --git a/src/add-ons/kernel/file_systems/nfs4/Request.cpp b/src/add-ons/kernel/file_systems/nfs4/Request.cpp index b4c4e43c24..b92d52898f 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Request.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Request.cpp @@ -45,7 +45,8 @@ Request::_SendUDP(Cookie* cookie) hard = fFileSystem->GetConfiguration().fHard; } - result = fServer->WaitCall(rpc); + result = fServer->WaitCall(rpc, + fFileSystem->GetConfiguration().fRequestTimeout); if (result != B_OK) { int attempts = 1; while (result != B_OK && (hard || attempts++ < retryLimit)) { @@ -56,7 +57,8 @@ Request::_SendUDP(Cookie* cookie) return result; } - result = fServer->WaitCall(rpc); + result = fServer->WaitCall(rpc, + fFileSystem->GetConfiguration().fRequestTimeout); } if (result != B_OK) { @@ -113,7 +115,8 @@ Request::_SendTCP(Cookie* cookie) if (cookie != NULL) cookie->RegisterRequest(rpc); - result = fServer->WaitCall(rpc); + result = fServer->WaitCall(rpc, + fFileSystem->GetConfiguration().fRequestTimeout); if (result != B_OK) { if (cookie != NULL) cookie->UnregisterRequest(rpc); 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 abc4607ea4..af25fde721 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -63,6 +63,7 @@ CreateNFS4Server(RPC::Server* serv) // Available options: // hard - retry requests until success // soft - retry requests no more than retrans times (default) +// timeo=X - request time limit before next retransmission (default: 60s) // retrans=X - retry requests X times (default: 5) // ac - use metadata cache (default) // noac - do not use metadata cache @@ -101,6 +102,7 @@ ParseArguments(const char* _args, PeerAddress* address, char** _path, conf->fHard = false; conf->fRetryLimit = 5; + conf->fRequestTimeout = sSecToBigTime(60); conf->fEmulateNamedAttrs = false; conf->fCacheMetadata = true; @@ -116,6 +118,9 @@ ParseArguments(const char* _args, PeerAddress* address, char** _path, else if (strncmp(options, "retrans=", 8) == 0) { options += strlen("retrans="); conf->fRetryLimit = atoi(options); + } else if (strncmp(options, "timeo=", 6) == 0) { + options += strlen("timeo="); + conf->fRequestTimeout = atoi(options); } else if (strcmp(options, "noac") == 0) conf->fCacheMetadata = false; else if (strcmp(options, "xattr-emu") == 0) From e4cd963ff11902f6b5351314614530a7e3b40272 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Tue, 8 Jan 2013 05:48:08 +0100 Subject: [PATCH 233/252] nfs4: Use default request timeout if FileSystem not given --- src/add-ons/kernel/file_systems/nfs4/Request.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Request.cpp b/src/add-ons/kernel/file_systems/nfs4/Request.cpp index b92d52898f..b8e8f9663d 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Request.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Request.cpp @@ -38,15 +38,17 @@ Request::_SendUDP(Cookie* cookie) if (cookie != NULL) cookie->RegisterRequest(rpc); + int requestTimeout = sSecToBigTime(60); int retryLimit = 0; bool hard = true; + if (fFileSystem != NULL) { + requestTimeout = fFileSystem->GetConfiguration().fRequestTimeout; retryLimit = fFileSystem->GetConfiguration().fRetryLimit; hard = fFileSystem->GetConfiguration().fHard; } - result = fServer->WaitCall(rpc, - fFileSystem->GetConfiguration().fRequestTimeout); + result = fServer->WaitCall(rpc, requestTimeout); if (result != B_OK) { int attempts = 1; while (result != B_OK && (hard || attempts++ < retryLimit)) { @@ -57,8 +59,7 @@ Request::_SendUDP(Cookie* cookie) return result; } - result = fServer->WaitCall(rpc, - fFileSystem->GetConfiguration().fRequestTimeout); + result = fServer->WaitCall(rpc, requestTimeout); } if (result != B_OK) { @@ -95,10 +96,12 @@ Request::_SendTCP(Cookie* cookie) status_t result; int attempts = 0; + int requestTimeout = sSecToBigTime(60); int retryLimit = 0; bool hard = true; if (fFileSystem != NULL) { + requestTimeout = fFileSystem->GetConfiguration().fRequestTimeout; retryLimit = fFileSystem->GetConfiguration().fRetryLimit; hard = fFileSystem->GetConfiguration().fHard; } @@ -115,8 +118,7 @@ Request::_SendTCP(Cookie* cookie) if (cookie != NULL) cookie->RegisterRequest(rpc); - result = fServer->WaitCall(rpc, - fFileSystem->GetConfiguration().fRequestTimeout); + result = fServer->WaitCall(rpc, requestTimeout); if (result != B_OK) { if (cookie != NULL) cookie->UnregisterRequest(rpc); From b8982d12b7c79396774816a1ceea995726bf21dd Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Tue, 8 Jan 2013 05:52:12 +0100 Subject: [PATCH 234/252] nfs4: Do not increment open owner sequence number when reusing lock owner --- src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp | 2 +- src/add-ons/kernel/file_systems/nfs4/OpenState.cpp | 12 +++++++++--- .../kernel/file_systems/nfs4/RequestBuilder.cpp | 5 +++-- .../kernel/file_systems/nfs4/RequestBuilder.h | 2 +- 4 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp index 9c374c931d..6118c42175 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Inode.cpp @@ -1105,7 +1105,7 @@ NFS4Inode::AcquireLock(OpenFileCookie* cookie, LockInfo* lockInfo, bool wait) RequestBuilder& req = request.Builder(); req.PutFH(fInfo.fHandle); - req.Lock(cookie->fOpenState, lockInfo, sequence); + req.Lock(cookie->fOpenState, lockInfo, &sequence); status_t result = request.Send(); if (result != B_OK) { diff --git a/src/add-ons/kernel/file_systems/nfs4/OpenState.cpp b/src/add-ons/kernel/file_systems/nfs4/OpenState.cpp index 13e2d50342..7ae795e779 100644 --- a/src/add-ons/kernel/file_systems/nfs4/OpenState.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/OpenState.cpp @@ -231,26 +231,32 @@ OpenState::_ReclaimLocks(uint64 newClientID) linfo->fOwner->fClientId = newClientID; } + uint32 sequence = fFileSystem->OpenOwnerSequenceLock(); do { RPC::Server* server = fFileSystem->Server(); Request request(server, fFileSystem); RequestBuilder& req = request.Builder(); req.PutFH(fInfo.fHandle); - req.Lock(this, linfo, true); + req.Lock(this, linfo, &sequence, true); status_t result = request.Send(); - if (result != B_OK) + if (result != B_OK) { + fFileSystem->OpenOwnerSequenceUnlock(sequence); break; + } ReplyInterpreter& reply = request.Reply(); - if (HandleErrors(reply.NFS4Error(), server)) + sequence += IncrementSequence(reply.NFS4Error()); + + if (HandleErrors(reply.NFS4Error(), server, NULL, NULL, &sequence)) continue; reply.PutFH(); reply.Lock(linfo); + fFileSystem->OpenOwnerSequenceUnlock(sequence); break; } while (true); locker.Unlock(); diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp index 3b8f69e376..e425e63a16 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp @@ -205,7 +205,7 @@ RequestBuilder::_GenerateLockOwner(XDR::WriteStream& stream, status_t -RequestBuilder::Lock(OpenState* state, LockInfo* lock, uint32 sequence, +RequestBuilder::Lock(OpenState* state, LockInfo* lock, uint32* sequence, bool reclaim) { if (fProcedure != ProcCompound) @@ -227,7 +227,7 @@ RequestBuilder::Lock(OpenState* state, LockInfo* lock, uint32 sequence, fRequest->Stream().AddBoolean(true); // new lock owner // open seq stateid - fRequest->Stream().AddUInt(sequence); + fRequest->Stream().AddUInt(*sequence); fRequest->Stream().AddUInt(state->fStateSeq); fRequest->Stream().AddUInt(state->fStateID[0]); fRequest->Stream().AddUInt(state->fStateID[1]); @@ -239,6 +239,7 @@ RequestBuilder::Lock(OpenState* state, LockInfo* lock, uint32 sequence, } else { fRequest->Stream().AddBoolean(false); // old lock owner + (*sequence)--; // lock stateid seq fRequest->Stream().AddUInt(lock->fOwner->fStateSeq); diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h index 1b0ea90dc3..6bf75248f9 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h @@ -42,7 +42,7 @@ public: status_t GetFH(); status_t Link(const char* name); status_t Lock(OpenState* state, LockInfo* lock, - uint32 sequence, bool reclaim = false); + uint32* sequence, bool reclaim = false); status_t LockT(LockType type, uint64 pos, uint64 len, OpenState* state); status_t LockU(LockInfo* lock); From d710e73de5d2f71b51133bb0e2e36113595d7945 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Tue, 8 Jan 2013 05:54:42 +0100 Subject: [PATCH 235/252] nfs4: Indentation fixes --- src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp index e425e63a16..02951f27fd 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp @@ -38,7 +38,7 @@ void RequestBuilder::_InitHeader() { fRequest = RPC::Call::Create(fProcedure, RPC::Auth::CreateSys(), - RPC::Auth::CreateNone()); + RPC::Auth::CreateNone()); if (fRequest == NULL) return; @@ -63,8 +63,7 @@ RequestBuilder::Access() fRequest->Stream().AddUInt(OpAccess); fRequest->Stream().AddUInt(ACCESS4_READ | ACCESS4_LOOKUP | ACCESS4_MODIFY - | ACCESS4_EXTEND | ACCESS4_DELETE - | ACCESS4_EXECUTE); + | ACCESS4_EXTEND | ACCESS4_DELETE | ACCESS4_EXECUTE); fOpCount++; return B_OK; From fea92e7bb3529b87f2cdce45448892644b1fa2fc Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Tue, 8 Jan 2013 18:57:14 +0100 Subject: [PATCH 236/252] nfs4: Save open mode in case of open reclaimation --- src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp index 7533b86408..6c9d0a70aa 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp @@ -59,6 +59,7 @@ Inode::CreateState(const char* name, int mode, int perms, OpenState* state, state->fFileSystem = fFileSystem; state->fInfo = fi; + state->fMode = mode & O_RWMASK; return B_OK; } @@ -117,6 +118,7 @@ Inode::Open(int mode, OpenFileCookie* cookie) state->fInfo = fInfo; state->fFileSystem = fFileSystem; + state->fMode = mode & O_RWMASK; status_t result = OpenFile(state, mode, &data); if (result != B_OK) return result; From bd19f23cecd6d1d73affbcd0c71fa1275eb17b73 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Tue, 8 Jan 2013 20:07:56 +0100 Subject: [PATCH 237/252] nfs4: Fix connection recovery code --- src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp | 2 +- src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp index c9b0867b2b..e92ede74ba 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp @@ -243,7 +243,7 @@ NFS4Server::_Renewal() } Request request(fServer, NULL); - request.Builder().Renew(fClientId); + request.Builder().Renew(clientId); request.Send(); switch (request.Reply().NFS4Error()) { diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp b/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp index 1b7ac54de5..f80633e906 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp @@ -141,7 +141,7 @@ Server::SendCallAsync(Call* call, Reply** reply, Request** request) ASSERT(reply != NULL); ASSERT(request != NULL); - if (fThreadError != B_OK) + if (fThreadError != B_OK && Repair() != B_OK) return fThreadError; Request* req = new(std::nothrow) Request; @@ -170,7 +170,7 @@ Server::ResendCallAsync(Call* call, Request* request) ASSERT(call != NULL); ASSERT(request != NULL); - if (fThreadError != B_OK) { + if (fThreadError != B_OK && Repair() != B_OK) { fRequests.FindRequest(request->fXID); delete request; return fThreadError; @@ -212,7 +212,7 @@ Server::Repair() uint32 thisRepair = fRepairCount; MutexLocker _(fRepairLock); - if (fRepairCount == thisRepair) + if (fRepairCount != thisRepair) return B_OK; fThreadCancel = true; From 9f12d1353a279af30633d591d85733b8f44257c0 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Tue, 8 Jan 2013 23:03:51 +0100 Subject: [PATCH 238/252] nfs4: Prevent OpenState::_ReclaimLocks from being called recursively When server reboots again when share reservations or locks are being reclaimed there is a risk that HandleErrors will invoke Reclaim(( again making it crash due to some double locks and more importantly making these two attempts to reclaim resources conflict and cause some much harder to recover from server errors. Instead all that, when server is rebooted again while recovering from previous reboot the recovery is aborted, the client retries its original request and then proper recovery occurs completly on a new server instance. --- src/add-ons/kernel/file_systems/nfs4/OpenState.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/OpenState.cpp b/src/add-ons/kernel/file_systems/nfs4/OpenState.cpp index 7ae795e779..21ac8d5b78 100644 --- a/src/add-ons/kernel/file_systems/nfs4/OpenState.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/OpenState.cpp @@ -186,8 +186,10 @@ OpenState::_ReclaimOpen(uint64 newClientID) sequence += IncrementSequence(reply.NFS4Error()); - if (HandleErrors(reply.NFS4Error(), server, NULL, NULL, &sequence)) + if (reply.NFS4Error() != NFS4ERR_STALE_CLIENTID + && HandleErrors(reply.NFS4Error(), server, NULL, NULL, &sequence)) { continue; + } reply.PutFH(); @@ -250,8 +252,12 @@ OpenState::_ReclaimLocks(uint64 newClientID) sequence += IncrementSequence(reply.NFS4Error()); - if (HandleErrors(reply.NFS4Error(), server, NULL, NULL, &sequence)) + if (reply.NFS4Error() != NFS4ERR_STALE_CLIENTID + && reply.NFS4Error() != NFS4ERR_STALE_STATEID + && HandleErrors(reply.NFS4Error(), server, NULL, NULL, + &sequence)) { continue; + } reply.PutFH(); reply.Lock(linfo); From 2d96a2b3038c96550dc94f43c7cc8f2ad06944ab Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Tue, 8 Jan 2013 23:46:04 +0100 Subject: [PATCH 239/252] nfs4: Minor improvements to memory deallocation in few places --- src/add-ons/kernel/file_systems/nfs4/Connection.cpp | 12 +++++------- src/add-ons/kernel/file_systems/nfs4/FileInfo.cpp | 7 +++---- src/add-ons/kernel/file_systems/nfs4/IdMap.cpp | 9 ++++----- 3 files changed, 12 insertions(+), 16 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Connection.cpp b/src/add-ons/kernel/file_systems/nfs4/Connection.cpp index e38953a3db..371cc395a6 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Connection.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Connection.cpp @@ -411,6 +411,7 @@ ConnectionStream::Receive(void** _buffer, uint32* _size) return B_NO_MEMORY; } else buffer = ptr; + MemoryDeleter bufferDeleter(buffer); received = 0; do { @@ -418,15 +419,12 @@ ConnectionStream::Receive(void** _buffer, uint32* _size) record_size - received, 0); received += result; } while (result > 0 && received < record_size); - if (result < 0) { - result = errno; - free(buffer); - return result; - } else if (result == 0) { - free(buffer); + if (result < 0) + return errno; + else if (result == 0) return ECONNABORTED; - } + bufferDeleter.Detach(); size += record_size; } while (!last_one); diff --git a/src/add-ons/kernel/file_systems/nfs4/FileInfo.cpp b/src/add-ons/kernel/file_systems/nfs4/FileInfo.cpp index 1a1edf33d0..6a208c1d9a 100644 --- a/src/add-ons/kernel/file_systems/nfs4/FileInfo.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/FileInfo.cpp @@ -58,6 +58,8 @@ FileInfo::CreateName(const char* dirPath, const char* name) if (fName == NULL) return B_NO_MEMORY; + free(const_cast(fPath)); + fPath = NULL; if (dirPath != NULL) { char* path = reinterpret_cast(malloc(strlen(name) + 2 + strlen(dirPath))); @@ -68,12 +70,9 @@ FileInfo::CreateName(const char* dirPath, const char* name) strcat(path, "/"); strcat(path, name); - free(const_cast(fPath)); fPath = path; - } else { - free(const_cast(fPath)); + } else fPath = strdup(name); - } if (fPath == NULL) return B_NO_MEMORY; diff --git a/src/add-ons/kernel/file_systems/nfs4/IdMap.cpp b/src/add-ons/kernel/file_systems/nfs4/IdMap.cpp index 146b07767c..a779469eb7 100644 --- a/src/add-ons/kernel/file_systems/nfs4/IdMap.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/IdMap.cpp @@ -9,6 +9,7 @@ #include "IdMap.h" +#include #include #include #include @@ -122,21 +123,19 @@ IdMap::_GetBuffer(T value, int32 code) void* buffer = malloc(size); if (buffer == NULL) return NULL; + MemoryDeleter bufferDeleter(buffer); size = read_port(fReplyPort, &code, buffer, size); if (size < B_OK) { - free(buffer); - if (_Repair() != B_OK) return 0; continue; } - if (code != MsgReply) { - free(buffer); + if (code != MsgReply) return NULL; - } + bufferDeleter.Detach(); return buffer; } while (true); } From 9c1d983eab87868914f3d1621fc028b883901cd5 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Tue, 8 Jan 2013 23:57:24 +0100 Subject: [PATCH 240/252] nfs4: Avoid using empty string for RootInode name --- src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp b/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp index 1b6031c8a9..1d3d096454 100644 --- a/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp @@ -190,8 +190,16 @@ FileSystem::Mount(FileSystem** _fs, RPC::Server* serv, const char* fsPath, if (name != NULL) { name++; reinterpret_cast(inode)->SetName(name); - } else + } else if (fsPath[0] != '\0') reinterpret_cast(inode)->SetName(fsPath); + else { + char* address = serv->ID().UniversalAddress(); + if (address != NULL) + reinterpret_cast(inode)->SetName(address); + else + reinterpret_cast(inode)->SetName("NFS4 Share"); + free(address); + } fs->fRoot = reinterpret_cast(inode); From 1c6f50254980bd074b0035b6bf459a3dec2ce4ee Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Wed, 16 Jan 2013 09:52:10 +0100 Subject: [PATCH 241/252] nfs4: Add not null assertions for Inode::fOpenState and fDelegation --- src/add-ons/kernel/file_systems/nfs4/Inode.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index 795a2a206b..e2f3241c6a 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -917,6 +917,8 @@ Inode::RecallReadDelegation() void Inode::ReturnDelegation(bool truncate) { + ASSERT(fDelegation != NULL); + fDelegation->GiveUp(truncate); fMetaCache.UnlockValid(); @@ -934,6 +936,8 @@ Inode::ReturnDelegation(bool truncate) void Inode::ReleaseOpenState() { + ASSERT(fOpenState != NULL); + if (fOpenState->ReleaseReference() == 1) fOpenState = NULL; } From 65edbee7c8940db313544516950b88bb5381fa70 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Wed, 16 Jan 2013 10:47:35 +0100 Subject: [PATCH 242/252] nfs4: DirectoryCache::GetSnapshot may return NULL --- .../kernel/file_systems/nfs4/DirectoryCache.h | 14 +++++++++----- src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp | 8 ++++++-- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.h b/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.h index 7abefb7d91..357ec6e213 100644 --- a/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.h +++ b/src/add-ons/kernel/file_systems/nfs4/DirectoryCache.h @@ -54,7 +54,7 @@ public: bool created = false); void RemoveEntry(const char* name); - inline DirectoryCacheSnapshot* GetSnapshot(); + inline status_t GetSnapshot(DirectoryCacheSnapshot** snapshot); inline SinglyLinkedList& EntriesList(); @@ -113,12 +113,16 @@ DirectoryCache::Valid() } -inline DirectoryCacheSnapshot* -DirectoryCache::GetSnapshot() +inline status_t +DirectoryCache::GetSnapshot(DirectoryCacheSnapshot** snapshot) { + ASSERT(snapshot != NULL); + + status_t result = B_OK; if (fDirectoryCache == NULL) - _LoadSnapshot(false); - return fDirectoryCache; + result = _LoadSnapshot(false); + *snapshot = fDirectoryCache; + return result; } diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp b/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp index 10d2943a6c..1b3851704c 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp @@ -324,8 +324,12 @@ Inode::ReadDir(void* _buffer, uint32 size, uint32* _count, return result; } - DirectoryCacheSnapshot* snapshot = cache->GetSnapshot(); - ASSERT(snapshot != NULL); + DirectoryCacheSnapshot* snapshot; + result = cache->GetSnapshot(&snapshot); + if (result != B_OK) { + cache->Unlock(); + return result; + } cookie->fSnapshot = new DirectoryCacheSnapshot(*snapshot); cache->Unlock(); From ce851e2bac9dba986b6e4243e4cccd6f4e59380c Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Thu, 17 Jan 2013 00:42:13 +0100 Subject: [PATCH 243/252] nfs4: Fix few Inode::fOpenState related race conditions --- src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp | 2 ++ src/add-ons/kernel/file_systems/nfs4/FileSystem.h | 10 ++++++++++ src/add-ons/kernel/file_systems/nfs4/Inode.h | 1 - src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp | 11 +++-------- .../kernel/file_systems/nfs4/kernel_interface.cpp | 3 +++ 5 files changed, 18 insertions(+), 9 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp b/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp index 1d3d096454..e76a010dea 100644 --- a/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp @@ -39,6 +39,7 @@ FileSystem::FileSystem(const MountConfiguration& configuration) mutex_init(&fOpenOwnerLock, NULL); mutex_init(&fOpenLock, NULL); mutex_init(&fDelegationLock, NULL); + mutex_init(&fCreateFileLock, NULL); } @@ -51,6 +52,7 @@ FileSystem::~FileSystem() mutex_destroy(&fDelegationLock); mutex_destroy(&fOpenLock); mutex_destroy(&fOpenOwnerLock); + mutex_destroy(&fCreateFileLock); free(const_cast(fPath)); delete fRoot; diff --git a/src/add-ons/kernel/file_systems/nfs4/FileSystem.h b/src/add-ons/kernel/file_systems/nfs4/FileSystem.h index 87fa4b9fb0..2d961b4f59 100644 --- a/src/add-ons/kernel/file_systems/nfs4/FileSystem.h +++ b/src/add-ons/kernel/file_systems/nfs4/FileSystem.h @@ -74,9 +74,12 @@ public: inline const MountConfiguration& GetConfiguration(); + inline mutex& CreateFileLock(); private: FileSystem(const MountConfiguration& config); + mutex fCreateFileLock; + mutex fDelegationLock; DoublyLinkedList fDelegationList; AVLTreeMap fHandleToDelegation; @@ -233,5 +236,12 @@ FileSystem::GetConfiguration() } +inline mutex& +FileSystem::CreateFileLock() +{ + return fCreateFileLock; +} + + #endif // FILESYSTEM_H diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h b/src/add-ons/kernel/file_systems/nfs4/Inode.h index da4802fe8c..6fd5d77166 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -221,7 +221,6 @@ inline void Inode::SetOpenState(OpenState* state) { ASSERT(state != NULL); - MutexLocker _(fStateLock); fOpenState = state; } diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp index 6c9d0a70aa..be6f926540 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp @@ -76,20 +76,15 @@ Inode::Create(const char* name, int mode, int perms, OpenFileCookie* cookie, cookie->fMode = mode; cookie->fLocks = NULL; - MutexLocker _(fStateLock); - OpenState* state = new OpenState; status_t result = CreateState(name, mode, perms, state, data); if (result != B_OK) return result; cookie->fOpenState = state; - fOpenState = state; + cookie->fFileSystem = fFileSystem; *id = FileIdToInoT(state->fInfo.fFileId); - cookie->fOpenState = fOpenState; - - cookie->fFileSystem = fFileSystem; fFileSystem->AddOpenFile(state); fFileSystem->Root()->MakeInfoInvalid(); @@ -125,9 +120,11 @@ Inode::Open(int mode, OpenFileCookie* cookie) fFileSystem->AddOpenFile(state); fOpenState = state; + cookie->fOpenState = state; locker.Unlock(); } else { fOpenState->AcquireReference(); + cookie->fOpenState = fOpenState; locker.Unlock(); int newMode = mode & O_RWMASK; @@ -167,8 +164,6 @@ Inode::Open(int mode, OpenFileCookie* cookie) file_cache_set_size(fFileCache, 0); } - cookie->fOpenState = fOpenState; - cookie->fFileSystem = fFileSystem; cookie->fMode = mode; cookie->fLocks = NULL; 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 af25fde721..7abba1c746 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -743,6 +743,9 @@ nfs4_create(fs_volume* volume, fs_vnode* dir, const char* name, int openMode, if (inode == NULL) return B_ENTRY_NOT_FOUND; + FileSystem* fs = reinterpret_cast(volume->private_volume); + MutexLocker createLocker(fs->CreateFileLock()); + OpenDelegationData data; status_t result = inode->Create(name, openMode, perms, cookie, &data, _newVnodeID); From 15a18a6b891de5945e958b4de54c0fbb462bc5fa Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Thu, 17 Jan 2013 03:54:33 +0100 Subject: [PATCH 244/252] nfs4: Fix write commit race condition --- src/add-ons/kernel/file_systems/nfs4/Inode.cpp | 6 +++++- src/add-ons/kernel/file_systems/nfs4/Inode.h | 1 + src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp | 9 ++++++--- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index e2f3241c6a..fe3d60d69c 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -37,6 +37,7 @@ Inode::Inode() rw_lock_init(&fDelegationLock, NULL); mutex_init(&fStateLock, NULL); mutex_init(&fFileCacheLock, NULL); + rw_lock_init(&fWriteLock, NULL); mutex_init(&fAIOLock, NULL); } @@ -147,6 +148,7 @@ Inode::~Inode() mutex_destroy(&fStateLock); mutex_destroy(&fFileCacheLock); rw_lock_destroy(&fDelegationLock); + rw_lock_destroy(&fWriteLock); ASSERT(fAIOCount == 0); } @@ -938,8 +940,10 @@ Inode::ReleaseOpenState() { ASSERT(fOpenState != NULL); - if (fOpenState->ReleaseReference() == 1) + if (fOpenState->ReleaseReference() == 1) { + ASSERT(fAIOCount == 0); fOpenState = NULL; + } } diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h b/src/add-ons/kernel/file_systems/nfs4/Inode.h index 6fd5d77166..0c5e8449fe 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -161,6 +161,7 @@ private: OpenState* fOpenState; mutex fStateLock; + rw_lock fWriteLock; bool fWriteDirty; sem_id fAIOWait; diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp index be6f926540..974827413b 100644 --- a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp @@ -36,8 +36,6 @@ Inode::CreateState(const char* name, int mode, int perms, OpenState* state, if (result != B_OK) return result; - RevalidateFileCache(); - FileInfo fi; fi.fFileId = fileID; fi.fHandle = handle; @@ -186,6 +184,7 @@ status_t Inode::Close(OpenFileCookie* cookie) { ASSERT(cookie != NULL); + ASSERT(fOpenState == cookie->fOpenState); SyncAndCommit(); @@ -371,8 +370,10 @@ Inode::WriteDirect(OpenStateCookie* cookie, off_t pos, const void* _buffer, state = cookie->fOpenState; } - if (!attribute) + if (!attribute) { + ReadLocker _(fWriteLock); fWriteDirty = true; + } while (size < *_length) { uint32 len = *_length - size; @@ -432,6 +433,8 @@ Inode::Write(OpenFileCookie* cookie, off_t pos, const void* _buffer, status_t Inode::Commit() { + WriteLocker _(fWriteLock); + if (!fWriteDirty) return B_OK; status_t result = CommitWrites(); From a0d5a922d6440c2d4df51536fab9ef5057e021f5 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Tue, 5 Feb 2013 03:20:37 +0100 Subject: [PATCH 245/252] nfs4: Try connecting to all getaddrinfo() results before giving up --- .../kernel/file_systems/nfs4/Connection.cpp | 98 +++++++++++++++---- .../kernel/file_systems/nfs4/Connection.h | 28 +++++- .../kernel/file_systems/nfs4/FileSystem.cpp | 7 +- .../kernel/file_systems/nfs4/RPCServer.cpp | 19 +++- .../kernel/file_systems/nfs4/RPCServer.h | 4 +- .../file_systems/nfs4/kernel_interface.cpp | 23 +++-- 6 files changed, 140 insertions(+), 39 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Connection.cpp b/src/add-ons/kernel/file_systems/nfs4/Connection.cpp index 371cc395a6..e9f86785da 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Connection.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Connection.cpp @@ -189,17 +189,36 @@ PeerAddress::InAddrSize() const } +AddressResolver::AddressResolver(const char* name) + : + fHead(NULL), + fCurrent(NULL), + fForcedPort(htons(NFS4_PORT)), + fForcedProtocol(IPPROTO_TCP) +{ + fStatus = ResolveAddress(name); +} + + +AddressResolver::~AddressResolver() +{ + freeaddrinfo(fHead); +} + + status_t -PeerAddress::ResolveName(const char* name, PeerAddress* address) +AddressResolver::ResolveAddress(const char* name) { ASSERT(name != NULL); - ASSERT(address != NULL); - address->fProtocol = IPPROTO_TCP; + if (fHead != NULL) { + freeaddrinfo(fHead); + fHead = NULL; + fCurrent = NULL; + } // getaddrinfo() is very expensive when called from kernel, so we do not // want to call it unless there is no other choice. - struct sockaddr_in addr; memset(&addr, 0, sizeof(addr)); if (inet_aton(name, &addr.sin_addr) == 1) { @@ -207,35 +226,74 @@ PeerAddress::ResolveName(const char* name, PeerAddress* address) addr.sin_family = AF_INET; addr.sin_port = htons(NFS4_PORT); - memcpy(&address->fAddress, &addr, sizeof(addr)); + memcpy(&fAddress.fAddress, &addr, sizeof(addr)); + fAddress.fProtocol = IPPROTO_TCP; return B_OK; } - addrinfo* ai; - status_t result = getaddrinfo(name, NULL, NULL, &ai); - if (result != B_OK) - return result; + status_t result = getaddrinfo(name, NULL, NULL, &fHead); + fCurrent = fHead; - addrinfo* current = ai; - while (current != NULL) { - if (current->ai_family == AF_INET) { - memcpy(&address->fAddress, current->ai_addr, sizeof(sockaddr_in)); + return result; +} + + +void +AddressResolver::ForceProtocol(const char* protocol) +{ + ASSERT(protocol != NULL); + + if (strcmp(protocol, "tcp") == 0) + fForcedProtocol = IPPROTO_TCP; + else if (strcmp(protocol, "udp") == 0) + fForcedProtocol = IPPROTO_UDP; + + fAddress.SetProtocol(protocol); +} + + +void +AddressResolver::ForcePort(uint16 port) +{ + fForcedPort = htons(port); + fAddress.SetPort(port); +} + + +status_t +AddressResolver::GetNextAddress(PeerAddress* address) +{ + ASSERT(address != NULL); + + if (fStatus != B_OK) + return fStatus; + + if (fHead == NULL) { + *address = fAddress; + fStatus = B_NAME_NOT_FOUND; + return B_OK; + } + + address->fProtocol = fForcedProtocol; + + while (fCurrent != NULL) { + if (fCurrent->ai_family == AF_INET) { + memcpy(&address->fAddress, fCurrent->ai_addr, sizeof(sockaddr_in)); reinterpret_cast(&address->fAddress)->sin_port - = htons(NFS4_PORT); - } else if (current->ai_family == AF_INET6) { - memcpy(&address->fAddress, current->ai_addr, sizeof(sockaddr_in6)); + = fForcedPort; + } else if (fCurrent->ai_family == AF_INET6) { + memcpy(&address->fAddress, fCurrent->ai_addr, sizeof(sockaddr_in6)); reinterpret_cast(&address->fAddress)->sin6_port - = htons(NFS4_PORT); + = fForcedPort; } else { - current = current->ai_next; + fCurrent = fCurrent->ai_next; continue; } - freeaddrinfo(ai); + fCurrent = fCurrent->ai_next; return B_OK; } - freeaddrinfo(ai); return B_NAME_NOT_FOUND; } diff --git a/src/add-ons/kernel/file_systems/nfs4/Connection.h b/src/add-ons/kernel/file_systems/nfs4/Connection.h index aceb2c0742..16f8062058 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Connection.h +++ b/src/add-ons/kernel/file_systems/nfs4/Connection.h @@ -38,9 +38,33 @@ struct PeerAddress { const void* InAddr() const; size_t InAddrSize() const; +}; - static status_t ResolveName(const char* name, - PeerAddress* address); +struct addrinfo; + +class AddressResolver { +public: + AddressResolver(const char* name); + ~AddressResolver(); + + status_t GetNextAddress(PeerAddress* address); + + void ForceProtocol(const char* protocol); + void ForcePort(uint16 port); + +protected: + status_t ResolveAddress(const char* name); + +private: + addrinfo* fHead; + addrinfo* fCurrent; + + PeerAddress fAddress; + + uint16 fForcedPort; + int fForcedProtocol; + + status_t fStatus; }; class ConnectionBase { diff --git a/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp b/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp index e76a010dea..a877cb9ded 100644 --- a/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp @@ -257,14 +257,11 @@ FileSystem::Migrate(const RPC::Server* serv) = reinterpret_cast(values[0].fData.fLocations); RPC::Server* server = fServer; - PeerAddress addr = fServer->ID(); for (uint32 i = 0; i < locs->fCount; i++) { for (uint32 j = 0; j < locs->fLocations[i].fCount; j++) { - if (PeerAddress::ResolveName(locs->fLocations[i].fLocations[j], - &addr) != B_OK) - continue; + AddressResolver resolver(locs->fLocations[i].fLocations[j]); - if (gRPCServerManager->Acquire(&fServer, addr, + if (gRPCServerManager->Acquire(&fServer, &resolver, CreateNFS4Server) == B_OK) { free(const_cast(fPath)); diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp b/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp index f80633e906..13f6a5fbb6 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp @@ -312,7 +312,24 @@ ServerManager::~ServerManager() status_t -ServerManager::Acquire(Server** _server, const PeerAddress& address, +ServerManager::Acquire(Server** _server, AddressResolver* resolver, + ProgramData* (*createPrivateData)(Server*)) +{ + PeerAddress address; + status_t result; + + while ((result = resolver->GetNextAddress(&address)) == B_OK) { + result = _Acquire(_server, address, createPrivateData); + if (result == B_OK) + break; + } + + return result; +} + + +status_t +ServerManager::_Acquire(Server** _server, const PeerAddress& address, ProgramData* (*createPrivateData)(Server*)) { ASSERT(_server != NULL); diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCServer.h b/src/add-ons/kernel/file_systems/nfs4/RPCServer.h index 738162d92f..9421049918 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RPCServer.h +++ b/src/add-ons/kernel/file_systems/nfs4/RPCServer.h @@ -171,11 +171,13 @@ public: ServerManager(); ~ServerManager(); - status_t Acquire(Server** _server, const PeerAddress& address, + status_t Acquire(Server** _server, AddressResolver* resolver, ProgramData* (*createPrivateData)(Server*)); void Release(Server* server); private: + status_t _Acquire(Server** _server, const PeerAddress& address, + ProgramData* (*createPrivateData)(Server*)); ServerNode* _Find(const PeerAddress& address); void _Delete(ServerNode* node); 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 7abba1c746..630e1e9f9a 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -72,7 +72,7 @@ CreateNFS4Server(RPC::Server* serv) // port=X - connect to port X (default: 2049) // proto=X - user transport protocol X (default: tcp) static status_t -ParseArguments(const char* _args, PeerAddress* address, char** _path, +ParseArguments(const char* _args, AddressResolver** address, char** _path, MountConfiguration* conf) { if (_args == NULL) @@ -92,13 +92,15 @@ ParseArguments(const char* _args, PeerAddress* address, char** _path, return B_MISMATCHED_VALUES; *path++ = '\0'; - status_t result = PeerAddress::ResolveName(args, address); - if (result != B_OK) - return result; + *address = new AddressResolver(args); + if (*address == NULL) + return B_NO_MEMORY; *_path = strdup(path); - if (*_path == NULL) + if (*_path == NULL) { + delete *address; return B_NO_MEMORY; + } conf->fHard = false; conf->fRetryLimit = 5; @@ -127,10 +129,10 @@ ParseArguments(const char* _args, PeerAddress* address, char** _path, conf->fEmulateNamedAttrs = true; else if (strncmp(options, "port=", 5) == 0) { options += strlen("port="); - address->SetPort(atoi(options)); + (*address)->ForcePort(atoi(options)); } else if (strncmp(options, "proto=", 6) == 0) { options += strlen("proto="); - address->SetProtocol(options); + (*address)->ForceProtocol(options); } options = optionsEnd; @@ -165,16 +167,17 @@ nfs4_mount(fs_volume* volume, const char* device, uint32 flags, } locker.Unlock(); - PeerAddress address; + AddressResolver* resolver; MountConfiguration config; char* path; - result = ParseArguments(args, &address, &path, &config); + result = ParseArguments(args, &resolver, &path, &config); if (result != B_OK) return result; MemoryDeleter pathDeleter(path); RPC::Server* server; - result = gRPCServerManager->Acquire(&server, address, CreateNFS4Server); + result = gRPCServerManager->Acquire(&server, resolver, CreateNFS4Server); + delete resolver; if (result != B_OK) return result; From 07b3bd59abde6a349ecca01a5042e7be828893b4 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Tue, 12 Feb 2013 23:05:32 +0100 Subject: [PATCH 246/252] nfs4: Correctly parse paths with '.' or '..' --- src/add-ons/kernel/file_systems/nfs4/FileInfo.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/FileInfo.cpp b/src/add-ons/kernel/file_systems/nfs4/FileInfo.cpp index 6a208c1d9a..5b7a57d776 100644 --- a/src/add-ons/kernel/file_systems/nfs4/FileInfo.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/FileInfo.cpp @@ -13,8 +13,6 @@ #include "Request.h" -// TODO: This function probably needs more strict checking against incorrect -// paths. Correct handling of '..' and '.' also may be useful. status_t FileInfo::ParsePath(RequestBuilder& req, uint32& count, const char* _path) { @@ -33,8 +31,13 @@ FileInfo::ParsePath(RequestBuilder& req, uint32& count, const char* _path) *pathEnd = '\0'; if (pathEnd != pathStart) { - req.LookUp(pathStart); - count++; + if (!strcmp(pathStart, "..")) { + req.LookUpUp(); + count++; + } else if (strcmp(pathStart, ".")) { + req.LookUp(pathStart); + count++; + } } if (pathEnd != NULL && pathEnd[1] != '\0') From 266b99b7e921a71c22ac5d444a107abb282bbf36 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Wed, 13 Feb 2013 01:14:45 +0100 Subject: [PATCH 247/252] nfs4: Support callbacks over IPv6 --- .../kernel/file_systems/nfs4/Connection.cpp | 62 ++++++++++++------- .../kernel/file_systems/nfs4/Connection.h | 16 ++++- .../kernel/file_systems/nfs4/RPCCallback.h | 19 ++++++ .../file_systems/nfs4/RPCCallbackServer.cpp | 55 ++++++++++++++-- .../file_systems/nfs4/RPCCallbackServer.h | 21 ++++--- .../kernel/file_systems/nfs4/RPCServer.cpp | 17 ++++- .../file_systems/nfs4/RequestBuilder.cpp | 30 +++++---- .../file_systems/nfs4/kernel_interface.cpp | 11 +--- 8 files changed, 172 insertions(+), 59 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Connection.cpp b/src/add-ons/kernel/file_systems/nfs4/Connection.cpp index e9f86785da..adc21d9859 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Connection.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Connection.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2012 Haiku, Inc. All rights reserved. + * Copyright 2012-2013 Haiku, Inc. All rights reserved. * Distributed under the terms of the MIT License. * * Authors: @@ -61,6 +61,26 @@ PeerAddress::PeerAddress() } +PeerAddress::PeerAddress(int networkFamily) + : + fProtocol(0) +{ + ASSERT(networkFamily == AF_INET || networkFamily == AF_INET6); + + memset(&fAddress, 0, sizeof(fAddress)); + + fAddress.ss_family = networkFamily; + switch (networkFamily) { + case AF_INET: + fAddress.ss_len = sizeof(sockaddr_in); + break; + case AF_INET6: + fAddress.ss_len = sizeof(sockaddr_in6); + break; + } +} + + const char* PeerAddress::ProtocolString() const { @@ -94,13 +114,11 @@ PeerAddress::SetProtocol(const char* protocol) char* PeerAddress::UniversalAddress() const { - const sockaddr* address = reinterpret_cast(&fAddress); - char* uAddr = reinterpret_cast(malloc(INET6_ADDRSTRLEN + 16)); if (uAddr == NULL) return NULL; - if (inet_ntop(address->sa_family, InAddr(), uAddr, AddressSize()) == NULL) + if (inet_ntop(fAddress.ss_family, InAddr(), uAddr, AddressSize()) == NULL) return NULL; char port[16]; @@ -114,7 +132,7 @@ PeerAddress::UniversalAddress() const socklen_t PeerAddress::AddressSize() const { - switch (reinterpret_cast(&fAddress)->sa_family) { + switch (Family()) { case AF_INET: return sizeof(sockaddr_in); case AF_INET6: @@ -130,7 +148,7 @@ PeerAddress::Port() const { uint16 port; - switch (reinterpret_cast(&fAddress)->sa_family) { + switch (Family()) { case AF_INET: port = reinterpret_cast(&fAddress)->sin_port; break; @@ -150,7 +168,7 @@ PeerAddress::SetPort(uint16 port) { port = htons(port); - switch (reinterpret_cast(&fAddress)->sa_family) { + switch (Family()) { case AF_INET: reinterpret_cast(&fAddress)->sin_port = port; break; @@ -160,11 +178,10 @@ PeerAddress::SetPort(uint16 port) } } - const void* PeerAddress::InAddr() const { - switch (reinterpret_cast(&fAddress)->sa_family) { + switch (Family()) { case AF_INET: return &reinterpret_cast(&fAddress)->sin_addr; case AF_INET6: @@ -178,7 +195,7 @@ PeerAddress::InAddr() const size_t PeerAddress::InAddrSize() const { - switch (reinterpret_cast(&fAddress)->sa_family) { + switch (Family()) { case AF_INET: return sizeof(in_addr); case AF_INET6: @@ -723,21 +740,23 @@ ConnectionBase::Disconnect() status_t -ConnectionListener::Listen(ConnectionListener** listener, uint16 port) +ConnectionListener::Listen(ConnectionListener** listener, int networkFamily, + uint16 port) { ASSERT(listener != NULL); + ASSERT(networkFamily == AF_INET || networkFamily == AF_INET6); - int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + int sock = socket(networkFamily, SOCK_STREAM, IPPROTO_TCP); if (sock < 0) return errno; - sockaddr_in addr; - memset(&addr, 0, sizeof(addr)); - addr.sin_len = sizeof(addr); - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = INADDR_ANY; - addr.sin_port = htons(port); - if (bind(sock, (struct sockaddr*)&addr, sizeof(addr)) != B_OK) { + PeerAddress address(networkFamily); + address.SetPort(port); + address.fProtocol = IPPROTO_TCP; + + status_t result = bind(sock, (sockaddr*)&address.fAddress, + address.AddressSize()); + if (result != B_OK) { close(sock); return errno; } @@ -747,17 +766,12 @@ ConnectionListener::Listen(ConnectionListener** listener, uint16 port) return errno; } - PeerAddress address; - address.fProtocol = IPPROTO_TCP; - memset(&address.fAddress, 0, sizeof(address.fAddress)); - *listener = new(std::nothrow) ConnectionListener(address); if (*listener == NULL) { close(sock); return B_NO_MEMORY; } - status_t result; if ((*listener)->fWaitCancel < B_OK) { result = (*listener)->fWaitCancel; close(sock); diff --git a/src/add-ons/kernel/file_systems/nfs4/Connection.h b/src/add-ons/kernel/file_systems/nfs4/Connection.h index 16f8062058..3c01daa6dd 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Connection.h +++ b/src/add-ons/kernel/file_systems/nfs4/Connection.h @@ -1,5 +1,5 @@ /* - * Copyright 2012 Haiku, Inc. All rights reserved. + * Copyright 2012-2013 Haiku, Inc. All rights reserved. * Distributed under the terms of the MIT License. * * Authors: @@ -25,6 +25,9 @@ struct PeerAddress { PeerAddress& operator=(const PeerAddress& address); PeerAddress(); + PeerAddress(int networkFamily); + + inline int Family() const; const char* ProtocolString() const; void SetProtocol(const char* protocol); @@ -40,6 +43,14 @@ struct PeerAddress { size_t InAddrSize() const; }; + +inline int +PeerAddress::Family() const +{ + return fAddress.ss_family; +} + + struct addrinfo; class AddressResolver { @@ -122,7 +133,8 @@ public: class ConnectionListener : public ConnectionBase { public: - static status_t Listen(ConnectionListener** listener, uint16 port = 0); + static status_t Listen(ConnectionListener** listener, int networkFamily, + uint16 port = 0); status_t AcceptConnection(Connection** connection); diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCCallback.h b/src/add-ons/kernel/file_systems/nfs4/RPCCallback.h index b729156bd0..9f579be9cf 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RPCCallback.h +++ b/src/add-ons/kernel/file_systems/nfs4/RPCCallback.h @@ -14,6 +14,7 @@ namespace RPC { +class CallbackServer; class CallbackRequest; class Server; @@ -24,10 +25,14 @@ public: inline void SetID(int32 id); inline int32 ID(); + inline void SetCBServer(CallbackServer* server); + inline CallbackServer* CBServer(); + status_t EnqueueRequest(CallbackRequest* request, Connection* connection); private: + CallbackServer* fCBServer; Server* fServer; int32 fID; }; @@ -47,6 +52,20 @@ Callback::ID() } +inline void +Callback::SetCBServer(CallbackServer* server) +{ + fCBServer = server; +} + + +inline CallbackServer* +Callback::CBServer() +{ + return fCBServer; +} + + } // namespace RPC diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCCallbackServer.cpp b/src/add-ons/kernel/file_systems/nfs4/RPCCallbackServer.cpp index f02a53c1bf..c296289d84 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RPCCallbackServer.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RPCCallbackServer.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2012 Haiku, Inc. All rights reserved. + * Copyright 2012-2013 Haiku, Inc. All rights reserved. * Distributed under the terms of the MIT License. * * Authors: @@ -13,22 +13,25 @@ #include "RPCCallback.h" #include "RPCCallbackReply.h" #include "RPCCallbackRequest.h" +#include "RPCServer.h" using namespace RPC; CallbackServer* gRPCCallbackServer = NULL; +CallbackServer* gRPCCallbackServer6 = NULL; -CallbackServer::CallbackServer() +CallbackServer::CallbackServer(int networkFamily) : fConnectionList(NULL), fListener(NULL), fThreadRunning(false), fCallbackArray(NULL), fArraySize(0), - fFreeSlot(-1) + fFreeSlot(-1), + fNetworkFamily(networkFamily) { mutex_init(&fConnectionLock, NULL); mutex_init(&fThreadLock, NULL); @@ -47,6 +50,47 @@ CallbackServer::~CallbackServer() } +CallbackServer* +CallbackServer::Get(Server* server) +{ + ASSERT(server != NULL); + + int family = server->ID().Family(); + ASSERT(family == AF_INET || family == AF_INET6); + + int idx; + switch (family) { + case AF_INET: + idx = 0; + break; + case AF_INET6: + idx = 1; + break; + default: + return NULL; + } + + MutexLocker _(fServerCreationLock); + if (fServers[idx] == NULL) + fServers[idx] = new CallbackServer(family); + return fServers[idx]; +} + + +void +CallbackServer::ShutdownAll() +{ + MutexLocker _(fServerCreationLock); + for (unsigned int i = 0; i < sizeof(fServers) / sizeof(fServers[0]); i++) + delete fServers[i]; + memset(&fServers, 0, sizeof(fServers)); +} + + +mutex CallbackServer::fServerCreationLock = MUTEX_INITIALIZER(NULL); +CallbackServer* CallbackServer::fServers[2] = { NULL, NULL }; + + status_t CallbackServer::RegisterCallback(Callback* callback) { @@ -82,6 +126,7 @@ CallbackServer::RegisterCallback(Callback* callback) fCallbackArray[id].fCallback = callback; callback->SetID(id); + callback->SetCBServer(this); return B_OK; } @@ -91,6 +136,7 @@ status_t CallbackServer::UnregisterCallback(Callback* callback) { ASSERT(callback != NULL); + ASSERT(callback->CBServer() == this); int32 id = callback->ID(); @@ -98,6 +144,7 @@ CallbackServer::UnregisterCallback(Callback* callback) fCallbackArray[id].fNext = fFreeSlot; fFreeSlot = id; + callback->SetCBServer(NULL); return B_OK; } @@ -109,7 +156,7 @@ CallbackServer::StartServer() if (fThreadRunning) return B_OK; - status_t result = ConnectionListener::Listen(&fListener); + status_t result = ConnectionListener::Listen(&fListener, fNetworkFamily); if (result != B_OK) return result; diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCCallbackServer.h b/src/add-ons/kernel/file_systems/nfs4/RPCCallbackServer.h index 8a5f67b816..fce7354b02 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RPCCallbackServer.h +++ b/src/add-ons/kernel/file_systems/nfs4/RPCCallbackServer.h @@ -1,5 +1,5 @@ /* - * Copyright 2012 Haiku, Inc. All rights reserved. + * Copyright 2012-2013 Haiku, Inc. All rights reserved. * Distributed under the terms of the MIT License. * * Authors: @@ -17,6 +17,7 @@ namespace RPC { class Callback; +class Server; struct ConnectionEntry { Connection* fConnection; @@ -33,13 +34,16 @@ union CallbackSlot { class CallbackServer { public: - CallbackServer(); + CallbackServer(int networkFamily); ~CallbackServer(); + static CallbackServer* Get(Server* server); + static void ShutdownAll(); + status_t RegisterCallback(Callback* callback); status_t UnregisterCallback(Callback* callback); - inline PeerAddress LocalID(); + inline PeerAddress LocalID(); protected: status_t StartServer(); @@ -57,6 +61,9 @@ protected: inline Callback* GetCallback(int32 id); private: + static mutex fServerCreationLock; + static CallbackServer* fServers[2]; + mutex fConnectionLock; ConnectionEntry* fConnectionList; ConnectionListener* fListener; @@ -69,6 +76,8 @@ private: CallbackSlot* fCallbackArray; uint32 fArraySize; int32 fFreeSlot; + + int fNetworkFamily; }; @@ -76,6 +85,8 @@ inline PeerAddress CallbackServer::LocalID() { PeerAddress address; + + ASSERT(fListener != NULL); fListener->GetLocalAddress(&address); return address; } @@ -93,9 +104,5 @@ CallbackServer::GetCallback(int32 id) } // namespace RPC - -extern RPC::CallbackServer* gRPCCallbackServer; - - #endif // RPCCALLBACKSERVER_H diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp b/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp index 13f6a5fbb6..9506af64e5 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp @@ -97,7 +97,7 @@ Server::Server(Connection* connection, PeerAddress* address) Server::~Server() { if (fCallback != NULL) - gRPCCallbackServer->UnregisterCallback(fCallback); + fCallback->CBServer()->UnregisterCallback(fCallback); delete fCallback; mutex_destroy(&fCallbackLock); mutex_destroy(&fRepairLock); @@ -235,9 +235,22 @@ Callback* Server::GetCallback() { MutexLocker _(fCallbackLock); + if (fCallback == NULL) { fCallback = new(std::nothrow) Callback(this); - gRPCCallbackServer->RegisterCallback(fCallback); + if (fCallback == NULL) + return NULL; + + CallbackServer* server = CallbackServer::Get(this); + if (server == NULL) { + delete fCallback; + return NULL; + } + + if (server->RegisterCallback(fCallback) != B_OK) { + delete fCallback; + return NULL; + } } return fCallback; diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp index 02951f27fd..83ff3b4cf8 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp @@ -671,21 +671,29 @@ RequestBuilder::SetClientID(RPC::Server* server) fRequest->Stream().AddUInt(0x40000000); - uint32 id = server->GetCallback()->ID(); + if (server->GetCallback() != NULL) { + ASSERT(server->GetCallback()->CBServer() != NULL); - PeerAddress local = gRPCCallbackServer->LocalID(); - PeerAddress servAddr = server->LocalID(); - servAddr.SetPort(local.Port()); + uint32 id = server->GetCallback()->ID(); - fRequest->Stream().AddString(local.ProtocolString()); + PeerAddress local = server->GetCallback()->CBServer()->LocalID(); + PeerAddress servAddr = server->LocalID(); + servAddr.SetPort(local.Port()); - char* uAddr = servAddr.UniversalAddress(); - if (uAddr == NULL) - return B_NO_MEMORY; - fRequest->Stream().AddString(uAddr); - free(uAddr); + fRequest->Stream().AddString(local.ProtocolString()); - fRequest->Stream().AddUInt(id); + char* uAddr = servAddr.UniversalAddress(); + if (uAddr == NULL) + return B_NO_MEMORY; + fRequest->Stream().AddString(uAddr); + free(uAddr); + + fRequest->Stream().AddUInt(id); + } else { + fRequest->Stream().AddString(""); + fRequest->Stream().AddString(""); + fRequest->Stream().AddUInt(0); + } fOpCount++; 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 630e1e9f9a..5a93ea5aa0 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -1367,14 +1367,6 @@ nfs4_init() return B_NO_MEMORY; } - gRPCCallbackServer = new(std::nothrow) RPC::CallbackServer; - if (gRPCCallbackServer == NULL) { - mutex_destroy(&gIdMapperLock); - delete gWorkQueue; - delete gRPCServerManager; - return B_NO_MEMORY; - } - return B_OK; } @@ -1382,7 +1374,8 @@ nfs4_init() status_t nfs4_uninit() { - delete gRPCCallbackServer; + RPC::CallbackServer::ShutdownAll(); + delete gIdMapper; delete gWorkQueue; delete gRPCServerManager; From a4caa431e4d815581cbd0e71ff0644d2b260d0ec Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Wed, 13 Feb 2013 20:21:53 +0100 Subject: [PATCH 248/252] nfs4: Make sure Request::fNext is initially NULL --- src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp | 1 + src/add-ons/kernel/file_systems/nfs4/RPCServer.h | 9 ++++++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp b/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp index 9506af64e5..811d3d4a5a 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp @@ -46,6 +46,7 @@ RequestManager::AddRequest(Request* request) else fQueueHead = request; fQueueTail = request; + request->fNext = NULL; } diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCServer.h b/src/add-ons/kernel/file_systems/nfs4/RPCServer.h index 9421049918..35c52f8bc1 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RPCServer.h +++ b/src/add-ons/kernel/file_systems/nfs4/RPCServer.h @@ -41,6 +41,9 @@ public: private: mutex fLock; + + // Neither SinglyLinkedList nor DoublyLinkedList is what we want + // here. And DoublyLinkedQueue is not even a queue. Request* fQueueHead; Request* fQueueTail; @@ -72,8 +75,8 @@ public: status_t Repair(); - inline const PeerAddress& ID() const; - inline PeerAddress LocalID() const; + inline const PeerAddress& ID() const; + inline PeerAddress LocalID() const; inline ProgramData* PrivateData(); inline void SetPrivateData(ProgramData* privateData); @@ -94,7 +97,7 @@ private: RequestManager fRequests; Connection* fConnection; - const PeerAddress* fAddress; + const PeerAddress* fAddress; ProgramData* fPrivateData; From c65f77dc10eed76812e0e605030970c29a8cde34 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Thu, 14 Feb 2013 01:37:09 +0100 Subject: [PATCH 249/252] nfs4: Make TRACE format strings 32/64 bit independent --- .../kernel/file_systems/nfs4/FileSystem.cpp | 3 +- .../file_systems/nfs4/kernel_interface.cpp | 103 +++++++++--------- 2 files changed, 55 insertions(+), 51 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp b/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp index a877cb9ded..309f572d28 100644 --- a/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp @@ -220,8 +220,7 @@ FileSystem::GetInode(ino_t id, Inode** _inode) FileInfo fi; status_t result = fInoIdMap.GetFileInfo(&fi, id); - if (result == B_ENTRY_NOT_FOUND) - dprintf("NFS4: unknown inode: %llu\n", id); + ASSERT(result != B_ENTRY_NOT_FOUND); if (result != B_OK) return result; 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 5a93ea5aa0..6e365082ba 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -7,6 +7,8 @@ */ +#define __STDC_FORMAT_MACROS +#include #include #include @@ -148,8 +150,8 @@ static status_t nfs4_mount(fs_volume* volume, const char* device, uint32 flags, const char* args, ino_t* _rootVnodeID) { - TRACE("volume = %p, device = %s, flags = %lu, args = %s", volume, device, - flags, args); + TRACE("volume = %p, device = %s, flags = %" PRIu32 ", args = %s", volume, + device, flags, args); status_t result; @@ -214,7 +216,7 @@ nfs4_mount(fs_volume* volume, const char* device, uint32 flags, *_rootVnodeID = inode->ID(); - TRACE("*_rootVnodeID = %llu", inode->ID()); + TRACE("*_rootVnodeID = %" PRIi64, inode->ID()); return B_OK; } @@ -225,7 +227,7 @@ nfs4_get_vnode(fs_volume* volume, ino_t id, fs_vnode* vnode, int* _type, uint32* _flags, bool reenter) { FileSystem* fs = reinterpret_cast(volume->private_volume); - TRACE("volume = %p, id = %llu", volume, id); + TRACE("volume = %p, id = %" PRIi64, volume, id); VnodeToInode* vnodeToInode = new VnodeToInode(id, fs); if (vnodeToInode == NULL) @@ -289,14 +291,14 @@ nfs4_lookup(fs_volume* volume, fs_vnode* dir, const char* name, ino_t* _id) if (inode == NULL) return B_ENTRY_NOT_FOUND; - TRACE("volume = %p, dir = %llu, name = %s", volume, vti->ID(), name); + TRACE("volume = %p, dir = %" PRIi64 ", name = %s", volume, vti->ID(), name); status_t result = inode->LookUp(name, _id); if (result != B_OK) return result; locker.Unlock(); - TRACE("*_id = %llu", *_id); + TRACE("*_id = %" PRIi64, *_id); // If VTI holds an outdated Inode next operation performed on it will // return either ERR_STALE or ERR_FHEXPIRED. Both of these error codes @@ -317,7 +319,7 @@ nfs4_get_vnode_name(fs_volume* volume, fs_vnode* vnode, char* buffer, size_t bufferSize) { VnodeToInode* vti = reinterpret_cast(vnode->private_node); - TRACE("volume = %p, vnode = %llu", volume, vti->ID()); + TRACE("volume = %p, vnode = %" PRIi64, volume, vti->ID()); VnodeToInodeLocker _(vti); Inode* inode = vti->Get(); @@ -333,7 +335,7 @@ static status_t nfs4_put_vnode(fs_volume* volume, fs_vnode* vnode, bool reenter) { VnodeToInode* vti = reinterpret_cast(vnode->private_node); - TRACE("volume = %p, vnode = %llu", volume, vti->ID()); + TRACE("volume = %p, vnode = %" PRIi64, volume, vti->ID()); delete vti; return B_OK; @@ -345,7 +347,7 @@ nfs4_remove_vnode(fs_volume* volume, fs_vnode* vnode, bool reenter) { FileSystem* fs = reinterpret_cast(volume->private_volume); VnodeToInode* vti = reinterpret_cast(vnode->private_node); - TRACE("volume = %p, vnode = %llu", volume, vti->ID()); + TRACE("volume = %p, vnode = %" PRIi64, volume, vti->ID()); if (fs->Root() == vti->GetPointer()) return B_OK; @@ -362,8 +364,8 @@ nfs4_read_pages(fs_volume* _volume, fs_vnode* vnode, void* _cookie, off_t pos, const iovec* vecs, size_t count, size_t* _numBytes) { VnodeToInode* vti = reinterpret_cast(vnode->private_node); - TRACE("volume = %p, vnode = %llu, cookie = %p, pos = %llu, " \ - "count = %lu, numBytes = %lu", _volume, vti->ID(), _cookie, pos, + TRACE("volume = %p, vnode = %" PRIi64 ", cookie = %p, pos = %" PRIi64 \ + ", count = %lu, numBytes = %lu", _volume, vti->ID(), _cookie, pos, count, *_numBytes); VnodeToInodeLocker _(vti); @@ -406,8 +408,8 @@ nfs4_write_pages(fs_volume* _volume, fs_vnode* vnode, void* _cookie, off_t pos, const iovec* vecs, size_t count, size_t* _numBytes) { VnodeToInode* vti = reinterpret_cast(vnode->private_node); - TRACE("volume = %p, vnode = %llu, cookie = %p, pos = %llu, " \ - "count = %lu, numBytes = %lu", _volume, vti->ID(), _cookie, pos, + TRACE("volume = %p, vnode = %" PRIi64 ", cookie = %p, pos = %" PRIi64 \ + ", count = %lu, numBytes = %lu", _volume, vti->ID(), _cookie, pos, count, *_numBytes); VnodeToInodeLocker _(vti); @@ -446,7 +448,7 @@ static status_t nfs4_io(fs_volume* volume, fs_vnode* vnode, void* cookie, io_request* request) { VnodeToInode* vti = reinterpret_cast(vnode->private_node); - TRACE("volume = %p, vnode = %llu, cookie = %p", volume, vti->ID(), + TRACE("volume = %p, vnode = %" PRIi64 ", cookie = %p", volume, vti->ID(), cookie); VnodeToInodeLocker _(vti); @@ -481,7 +483,7 @@ nfs4_get_file_map(fs_volume* volume, fs_vnode* vnode, off_t _offset, static status_t nfs4_set_flags(fs_volume* volume, fs_vnode* vnode, void* _cookie, int flags) { - TRACE("volume = %p, vnode = %llu, cookie = %p, flags = %d", volume, + TRACE("volume = %p, vnode = %" PRIi64 ", cookie = %p, flags = %d", volume, reinterpret_cast(vnode->private_node)->ID(), _cookie, flags); @@ -495,7 +497,7 @@ static status_t nfs4_fsync(fs_volume* volume, fs_vnode* vnode) { VnodeToInode* vti = reinterpret_cast(vnode->private_node); - TRACE("volume = %p, vnode = %llu", volume, vti->ID()); + TRACE("volume = %p, vnode = %" PRIi64, volume, vti->ID()); VnodeToInodeLocker _(vti); Inode* inode = vti->Get(); @@ -511,7 +513,7 @@ nfs4_read_symlink(fs_volume* volume, fs_vnode* link, char* buffer, size_t* _bufferSize) { VnodeToInode* vti = reinterpret_cast(link->private_node); - TRACE("volume = %p, link = %llu", volume, vti->ID()); + TRACE("volume = %p, link = %" PRIi64, volume, vti->ID()); VnodeToInodeLocker _(vti); Inode* inode = vti->Get(); @@ -527,8 +529,8 @@ nfs4_create_symlink(fs_volume* volume, fs_vnode* dir, const char* name, const char* path, int mode) { VnodeToInode* vti = reinterpret_cast(dir->private_node); - TRACE("volume = %p, dir = %llu, name = %s, path = %s, mode = %d", volume, - vti->ID(), name, path, mode); + TRACE("volume = %p, dir = %" PRIi64 ", name = %s, path = %s, mode = %d", + volume, vti->ID(), name, path, mode); VnodeToInodeLocker _(vti); Inode* inode = vti->Get(); @@ -556,7 +558,7 @@ nfs4_link(fs_volume* volume, fs_vnode* dir, const char* name, fs_vnode* vnode) { VnodeToInode* vti = reinterpret_cast(vnode->private_node); VnodeToInode* dirVti = reinterpret_cast(dir->private_node); - TRACE("volume = %p, dir = %llu, name = %s, vnode = %llu", volume, + TRACE("volume = %p, dir = %" PRIi64 ", name = %s, vnode = %" PRIi64, volume, dirVti->ID(), name, vti->ID()); VnodeToInodeLocker _dir(dirVti); @@ -584,7 +586,7 @@ nfs4_unlink(fs_volume* volume, fs_vnode* dir, const char* name) if (inode == NULL) return B_ENTRY_NOT_FOUND; - TRACE("volume = %p, dir = %llu, name = %s", volume, vti->ID(), name); + TRACE("volume = %p, dir = %" PRIi64 ", name = %s", volume, vti->ID(), name); ino_t id; status_t result = inode->Remove(name, NF4REG, &id); @@ -613,9 +615,9 @@ nfs4_rename(fs_volume* volume, fs_vnode* fromDir, const char* fromName, VnodeToInode* fromVti = reinterpret_cast(fromDir->private_node); VnodeToInode* toVti = reinterpret_cast(toDir->private_node); - TRACE("volume = %p, fromDir = %llu, toDir = %llu, fromName = %s, " \ - "toName = %s", volume, fromVti->ID(), toVti->ID(), fromName, - toName); + TRACE("volume = %p, fromDir = %" PRIi64 ", toDir = %" PRIi64 "," \ + " fromName = %s, toName = %s", volume, fromVti->ID(), toVti->ID(), \ + fromName, toName); VnodeToInodeLocker _from(fromVti); Inode* fromInode = fromVti->Get(); @@ -652,7 +654,8 @@ static status_t nfs4_access(fs_volume* volume, fs_vnode* vnode, int mode) { VnodeToInode* vti = reinterpret_cast(vnode->private_node); - TRACE("volume = %p, vnode = %llu, mode = %d", volume, vti->ID(), mode); + TRACE("volume = %p, vnode = %" PRIi64 ", mode = %d", volume, vti->ID(), + mode); VnodeToInodeLocker _(vti); Inode* inode = vti->Get(); @@ -667,7 +670,7 @@ static status_t nfs4_read_stat(fs_volume* volume, fs_vnode* vnode, struct stat* stat) { VnodeToInode* vti = reinterpret_cast(vnode->private_node); - TRACE("volume = %p, vnode = %llu", volume, vti->ID()); + TRACE("volume = %p, vnode = %" PRIi64, volume, vti->ID()); VnodeToInodeLocker _(vti); Inode* inode = vti->Get(); @@ -683,8 +686,8 @@ nfs4_write_stat(fs_volume* volume, fs_vnode* vnode, const struct stat* stat, uint32 statMask) { VnodeToInode* vti = reinterpret_cast(vnode->private_node); - TRACE("volume = %p, vnode = %llu, statMask = %lu", volume, vti->ID(), - statMask); + TRACE("volume = %p, vnode = %" PRIi64 ", statMask = %" PRIu32, volume, + vti->ID(), statMask); VnodeToInodeLocker _(vti); Inode* inode = vti->Get(); @@ -738,8 +741,8 @@ nfs4_create(fs_volume* volume, fs_vnode* dir, const char* name, int openMode, *_cookie = cookie; VnodeToInode* vti = reinterpret_cast(dir->private_node); - TRACE("volume = %p, dir = %llu, name = %s, openMode = %d, perms = %d", - volume, vti->ID(), name, openMode, perms); + TRACE("volume = %p, dir = %" PRIi64 ", name = %s, openMode = %d," \ + " perms = %d", volume, vti->ID(), name, openMode, perms); VnodeToInodeLocker _(vti); Inode* inode = vti->Get(); @@ -784,7 +787,7 @@ nfs4_create(fs_volume* volume, fs_vnode* dir, const char* name, int openMode, } } - TRACE("*cookie = %p, *newVnodeID = %llu", *_cookie, *_newVnodeID); + TRACE("*cookie = %p, *newVnodeID = %" PRIi64, *_cookie, *_newVnodeID); return result; } @@ -793,7 +796,7 @@ static status_t nfs4_open(fs_volume* volume, fs_vnode* vnode, int openMode, void** _cookie) { VnodeToInode* vti = reinterpret_cast(vnode->private_node); - TRACE("volume = %p, vnode = %llu, openMode = %d", volume, vti->ID(), + TRACE("volume = %p, vnode = %" PRIi64 ", openMode = %d", volume, vti->ID(), openMode); VnodeToInodeLocker _(vti); @@ -826,7 +829,7 @@ nfs4_close(fs_volume* volume, fs_vnode* vnode, void* _cookie) { VnodeToInode* vti = reinterpret_cast(vnode->private_node); - TRACE("volume = %p, vnode = %llu, cookie = %p", volume, vti->ID(), + TRACE("volume = %p, vnode = %" PRIi64 ", cookie = %p", volume, vti->ID(), _cookie); VnodeToInodeLocker _(vti); @@ -848,7 +851,7 @@ nfs4_free_cookie(fs_volume* volume, fs_vnode* vnode, void* _cookie) { VnodeToInode* vti = reinterpret_cast(vnode->private_node); - TRACE("volume = %p, vnode = %llu, cookie = %p", volume, vti->ID(), + TRACE("volume = %p, vnode = %" PRIi64 ", cookie = %p", volume, vti->ID(), _cookie); VnodeToInodeLocker _(vti); @@ -873,8 +876,8 @@ nfs4_read(fs_volume* volume, fs_vnode* vnode, void* _cookie, off_t pos, void* buffer, size_t* length) { VnodeToInode* vti = reinterpret_cast(vnode->private_node); - TRACE("volume = %p, vnode = %llu, cookie = %p, pos = %llu, length = %lu", - volume, vti->ID(), _cookie, pos, *length); + TRACE("volume = %p, vnode = %" PRIi64 ", cookie = %p, pos = %" PRIi64 \ + ", length = %lu", volume, vti->ID(), _cookie, pos, *length); VnodeToInodeLocker _(vti); Inode* inode = vti->Get(); @@ -898,8 +901,8 @@ nfs4_write(fs_volume* volume, fs_vnode* vnode, void* _cookie, off_t pos, const void* _buffer, size_t* length) { VnodeToInode* vti = reinterpret_cast(vnode->private_node); - TRACE("volume = %p, vnode = %llu, cookie = %p, pos = %llu, length = %lu", - volume, vti->ID(), _cookie, pos, *length); + TRACE("volume = %p, vnode = %" PRIi64 ", cookie = %p, pos = %" PRIi64 \ + ", length = %lu", volume, vti->ID(), _cookie, pos, *length); VnodeToInodeLocker _(vti); Inode* inode = vti->Get(); @@ -923,7 +926,8 @@ nfs4_create_dir(fs_volume* volume, fs_vnode* parent, const char* name, int mode) { VnodeToInode* vti = reinterpret_cast(parent->private_node); - TRACE("volume = %p, parent = %llu, mode = %d", volume, vti->ID(), mode); + TRACE("volume = %p, parent = %" PRIi64 ", mode = %d", volume, vti->ID(), + mode); VnodeToInodeLocker _(vti); Inode* inode = vti->Get(); @@ -950,7 +954,8 @@ static status_t nfs4_remove_dir(fs_volume* volume, fs_vnode* parent, const char* name) { VnodeToInode* vti = reinterpret_cast(parent->private_node); - TRACE("volume = %p, parent = %llu, name = %s", volume, vti->ID(), name); + TRACE("volume = %p, parent = %" PRIi64 ", name = %s", volume, vti->ID(), + name); VnodeToInodeLocker _(vti); Inode* inode = vti->Get(); @@ -985,7 +990,7 @@ nfs4_open_dir(fs_volume* volume, fs_vnode* vnode, void** _cookie) *_cookie = cookie; VnodeToInode* vti = reinterpret_cast(vnode->private_node); - TRACE("volume = %p, vnode = %llu", volume, vti->ID()); + TRACE("volume = %p, vnode = %" PRIi64, volume, vti->ID()); VnodeToInodeLocker _(vti); Inode* inode = vti->Get(); @@ -1005,7 +1010,7 @@ nfs4_open_dir(fs_volume* volume, fs_vnode* vnode, void** _cookie) static status_t nfs4_close_dir(fs_volume* volume, fs_vnode* vnode, void* _cookie) { - TRACE("volume = %p, vnode = %llu, cookie = %p", volume, + TRACE("volume = %p, vnode = %" PRIi64 ", cookie = %p", volume, reinterpret_cast(vnode->private_node)->ID(), _cookie); Cookie* cookie = reinterpret_cast(_cookie); @@ -1016,7 +1021,7 @@ nfs4_close_dir(fs_volume* volume, fs_vnode* vnode, void* _cookie) static status_t nfs4_free_dir_cookie(fs_volume* volume, fs_vnode* vnode, void* cookie) { - TRACE("volume = %p, vnode = %llu, cookie = %p", volume, + TRACE("volume = %p, vnode = %" PRIi64 ", cookie = %p", volume, reinterpret_cast(vnode->private_node)->ID(), cookie); delete reinterpret_cast(cookie); @@ -1030,7 +1035,7 @@ nfs4_read_dir(fs_volume* volume, fs_vnode* vnode, void* _cookie, { OpenDirCookie* cookie = reinterpret_cast(_cookie); VnodeToInode* vti = reinterpret_cast(vnode->private_node); - TRACE("volume = %p, vnode = %llu, cookie = %p", volume, vti->ID(), + TRACE("volume = %p, vnode = %" PRIi64 ", cookie = %p", volume, vti->ID(), _cookie); VnodeToInodeLocker _(vti); @@ -1045,7 +1050,7 @@ nfs4_read_dir(fs_volume* volume, fs_vnode* vnode, void* _cookie, static status_t nfs4_rewind_dir(fs_volume* volume, fs_vnode* vnode, void* _cookie) { - TRACE("volume = %p, vnode = %llu, cookie = %p", volume, + TRACE("volume = %p, vnode = %" PRIi64 ", cookie = %p", volume, reinterpret_cast(vnode->private_node)->ID(), _cookie); OpenDirCookie* cookie = reinterpret_cast(_cookie); @@ -1069,7 +1074,7 @@ nfs4_open_attr_dir(fs_volume* volume, fs_vnode* vnode, void** _cookie) *_cookie = cookie; VnodeToInode* vti = reinterpret_cast(vnode->private_node); - TRACE("volume = %p, vnode = %llu", volume, vti->ID()); + TRACE("volume = %p, vnode = %" PRIi64, volume, vti->ID()); VnodeToInodeLocker _(vti); Inode* inode = vti->Get(); @@ -1292,7 +1297,7 @@ nfs4_test_lock(fs_volume* volume, fs_vnode* vnode, void* _cookie, { VnodeToInode* vti = reinterpret_cast(vnode->private_node); OpenFileCookie* cookie = reinterpret_cast(_cookie); - TRACE("volume = %p, vnode = %llu, cookie = %p, lock = %p", volume, + TRACE("volume = %p, vnode = %" PRIi64 ", cookie = %p, lock = %p", volume, vti->ID(), _cookie, lock); VnodeToInodeLocker _(vti); @@ -1310,7 +1315,7 @@ nfs4_acquire_lock(fs_volume* volume, fs_vnode* vnode, void* _cookie, { VnodeToInode* vti = reinterpret_cast(vnode->private_node); OpenFileCookie* cookie = reinterpret_cast(_cookie); - TRACE("volume = %p, vnode = %llu, cookie = %p, lock = %p", volume, + TRACE("volume = %p, vnode = %" PRIi64 ", cookie = %p, lock = %p", volume, vti->ID(), _cookie, lock); @@ -1329,7 +1334,7 @@ nfs4_release_lock(fs_volume* volume, fs_vnode* vnode, void* _cookie, const struct flock* lock) { VnodeToInode* vti = reinterpret_cast(vnode->private_node); - TRACE("volume = %p, vnode = %llu, cookie = %p, lock = %p", volume, + TRACE("volume = %p, vnode = %" PRIi64 ", cookie = %p, lock = %p", volume, vti->ID(), _cookie, lock); VnodeToInodeLocker _(vti); From 4c64bd932c634e7115a88d494de083dca7c9e20d Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Thu, 14 Feb 2013 01:43:17 +0100 Subject: [PATCH 250/252] nfs4: Fix wrong cast in nfs4_rename --- .../kernel/file_systems/nfs4/kernel_interface.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) 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 6e365082ba..b3366cf4fc 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -636,11 +636,16 @@ nfs4_rename(fs_volume* volume, fs_vnode* fromDir, const char* fromName, if (result != B_OK) return result; - Inode* child; - result = get_vnode(volume, id, reinterpret_cast(&child)); + VnodeToInode* vti; + result = get_vnode(volume, id, reinterpret_cast(&vti)); if (result == B_OK) { - unremove_vnode(volume, id); + Inode* child = vti->Get(); + if (child == NULL) { + put_vnode(volume, id); + return B_ENTRY_NOT_FOUND; + } + unremove_vnode(volume, id); child->fInfo.fParent = toInode->fInfo.fHandle; child->fInfo.CreateName(toInode->fInfo.fPath, toName); put_vnode(volume, id); From da95db10146a5ad0d619fee9ad970718302cf6c0 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Thu, 14 Feb 2013 18:13:59 +0100 Subject: [PATCH 251/252] nfs4: Fix {last_one,result} may be used uninitialized warnings --- src/add-ons/kernel/file_systems/nfs4/Connection.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Connection.cpp b/src/add-ons/kernel/file_systems/nfs4/Connection.cpp index adc21d9859..03de1c0750 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Connection.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Connection.cpp @@ -435,7 +435,7 @@ ConnectionStream::Receive(void** _buffer, uint32* _size) void* buffer = NULL; uint32 record_size; - bool last_one; + bool last_one = false; object_wait_info object[2]; object[0].object = fWaitCancel; @@ -688,6 +688,9 @@ Connection::Connect() addr6.sin6_port = htons(port); result = bind(fSocket, (struct sockaddr*)&addr6, sizeof(addr6)); break; + default: + result = EAFNOSUPPORT; + break; } } while (attempt <= 10 && result != B_OK); From 49518a1c1598060ed73e120faaf07b0b8a1681d8 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Thu, 14 Feb 2013 18:19:59 +0100 Subject: [PATCH 252/252] nfs4: Take advantage of PeerAddress class in Connection::Connect() --- .../kernel/file_systems/nfs4/Connection.cpp | 54 +++---------------- 1 file changed, 8 insertions(+), 46 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Connection.cpp b/src/add-ons/kernel/file_systems/nfs4/Connection.cpp index 03de1c0750..937e45ed1b 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Connection.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Connection.cpp @@ -636,15 +636,12 @@ Connection::SetTo(Connection **_connection, int socket, status_t Connection::Connect() { - const sockaddr& address - = *reinterpret_cast(&fPeerAddress); - switch (fPeerAddress.fProtocol) { case IPPROTO_TCP: - fSocket = socket(address.sa_family, SOCK_STREAM, IPPROTO_TCP); + fSocket = socket(fPeerAddress.Family(), SOCK_STREAM, IPPROTO_TCP); break; case IPPROTO_UDP: - fSocket = socket(address.sa_family, SOCK_DGRAM, IPPROTO_UDP); + fSocket = socket(fPeerAddress.Family(), SOCK_DGRAM, IPPROTO_UDP); break; default: return B_BAD_VALUE; @@ -655,21 +652,7 @@ Connection::Connect() status_t result; uint16 port, attempt = 0; - sockaddr_in addr; - sockaddr_in6 addr6; - switch (address.sa_family) { - case AF_INET: - memset(&addr, 0, sizeof(addr)); - addr.sin_len = sizeof(addr); - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = INADDR_ANY; - break; - case AF_INET6: - memset(&addr6, 0, sizeof(addr6)); - addr6.sin6_len = sizeof(addr6); - addr6.sin6_family = AF_INET6; - break; - } + PeerAddress address(fPeerAddress.Family()); do { port = rand() % (IPPORT_RESERVED - NFS_MIN_PORT); @@ -679,19 +662,9 @@ Connection::Connect() port = 0; attempt++; - switch (address.sa_family) { - case AF_INET: - addr.sin_port = htons(port); - result = bind(fSocket, (struct sockaddr*)&addr, sizeof(addr)); - break; - case AF_INET6: - addr6.sin6_port = htons(port); - result = bind(fSocket, (struct sockaddr*)&addr6, sizeof(addr6)); - break; - default: - result = EAFNOSUPPORT; - break; - } + address.SetPort(port); + result = bind(fSocket, (sockaddr*)&address.fAddress, + address.AddressSize()); } while (attempt <= 10 && result != B_OK); if (attempt > 10) { @@ -699,19 +672,8 @@ Connection::Connect() return result; } - socklen_t addressSize; - switch (address.sa_family) { - case AF_INET: - addressSize = sizeof(sockaddr_in); - break; - case AF_INET6: - addressSize = sizeof(sockaddr_in6); - break; - default: - return B_BAD_VALUE; - } - - result = connect(fSocket, &address, addressSize); + result = connect(fSocket, (sockaddr*)&fPeerAddress.fAddress, + fPeerAddress.AddressSize()); if (result != 0) { result = errno; close(fSocket);