lib/nfs: initial support for libnfs API 2

Commit
5e8f7ce273
introduced the libnfs API version 2 which may eventually become libnfs
version 6.

This version detection depends on my pull request
https://github.com/sahlberg/libnfs/pull/468
This commit is contained in:
Max Kellermann 2024-05-13 18:11:24 +02:00
parent 0ac24e5a24
commit 31e583e9f8
6 changed files with 82 additions and 7 deletions

1
NEWS
View File

@ -26,6 +26,7 @@ ver 0.24 (not yet released)
* storage * storage
- curl: optimize database update - curl: optimize database update
- nfs: require libnfs 4.0 or later - nfs: require libnfs 4.0 or later
- nfs: support libnfs 6 (API version 2)
- nfs: support libnfs URL arguments - nfs: support libnfs URL arguments
* input * input
- alsa: limit ALSA buffer time to 2 seconds - alsa: limit ALSA buffer time to 2 seconds

View File

@ -81,11 +81,25 @@ NfsConnection::CancellableCallback::Stat(nfs_context *ctx,
inline void inline void
NfsConnection::CancellableCallback::Read(nfs_context *ctx, struct nfsfh *fh, NfsConnection::CancellableCallback::Read(nfs_context *ctx, struct nfsfh *fh,
uint64_t offset, size_t size) uint64_t offset,
#ifdef LIBNFS_API_2
std::span<std::byte> dest
#else
std::size_t size
#endif
)
{ {
assert(connection.GetEventLoop().IsInside()); assert(connection.GetEventLoop().IsInside());
int result = nfs_pread_async(ctx, fh, offset, size, Callback, this); int result = nfs_pread_async(ctx, fh,
#ifdef LIBNFS_API_2
dest.data(), dest.size(),
#endif
offset,
#ifndef LIBNFS_API_2
size,
#endif
Callback, this);
if (result < 0) if (result < 0)
throw NfsClientError(ctx, "nfs_pread_async() failed"); throw NfsClientError(ctx, "nfs_pread_async() failed");
} }
@ -328,7 +342,12 @@ NfsConnection::Stat(struct nfsfh *fh, NfsCallback &callback)
} }
void void
NfsConnection::Read(struct nfsfh *fh, uint64_t offset, size_t size, NfsConnection::Read(struct nfsfh *fh, uint64_t offset,
#ifdef LIBNFS_API_2
std::span<std::byte> dest,
#else
std::size_t size,
#endif
NfsCallback &callback) NfsCallback &callback)
{ {
assert(GetEventLoop().IsInside()); assert(GetEventLoop().IsInside());
@ -336,7 +355,13 @@ NfsConnection::Read(struct nfsfh *fh, uint64_t offset, size_t size,
auto &c = callbacks.Add(callback, *this, false); auto &c = callbacks.Add(callback, *this, false);
try { try {
c.Read(context, fh, offset, size); c.Read(context, fh, offset,
#ifdef LIBNFS_API_2
dest
#else
size
#endif
);
} catch (...) { } catch (...) {
callbacks.Remove(c); callbacks.Remove(c);
throw; throw;

View File

@ -62,7 +62,13 @@ class NfsConnection {
void Open(nfs_context *context, const char *path, int flags); void Open(nfs_context *context, const char *path, int flags);
void Stat(nfs_context *context, struct nfsfh *fh); void Stat(nfs_context *context, struct nfsfh *fh);
void Read(nfs_context *context, struct nfsfh *fh, void Read(nfs_context *context, struct nfsfh *fh,
uint64_t offset, size_t size); uint64_t offset,
#ifdef LIBNFS_API_2
std::span<std::byte> dest
#else
std::size_t size
#endif
);
/** /**
* Cancel the operation and schedule a call to * Cancel the operation and schedule a call to
@ -210,7 +216,12 @@ public:
/** /**
* Throws on error. * Throws on error.
*/ */
void Read(struct nfsfh *fh, uint64_t offset, size_t size, void Read(struct nfsfh *fh, uint64_t offset,
#ifdef LIBNFS_API_2
std::span<std::byte> dest,
#else
std::size_t size,
#endif
NfsCallback &callback); NfsCallback &callback);
/** /**

View File

@ -59,7 +59,13 @@ NfsFileReader::CancelOrClose() noexcept
else if (state > State::OPEN) else if (state > State::OPEN)
/* one async operation in progress: cancel it and /* one async operation in progress: cancel it and
defer the nfs_close_async() call */ defer the nfs_close_async() call */
connection->CancelAndClose(fh, {}, *this); connection->CancelAndClose(fh,
#ifdef LIBNFS_API_2
ToDeleteArray(read_buffer.release()),
#else
{},
#endif
*this);
else if (state > State::MOUNT) else if (state > State::MOUNT)
/* we don't have a file handle yet - just cancel the /* we don't have a file handle yet - just cancel the
async operation */ async operation */
@ -116,7 +122,15 @@ NfsFileReader::Read(uint64_t offset, size_t size)
{ {
assert(state == State::IDLE); assert(state == State::IDLE);
#ifdef LIBNFS_API_2
assert(!read_buffer);
// TOOD read into caller-provided buffer
read_buffer = std::make_unique<std::byte[]>(size);
connection->Read(fh, offset, {read_buffer.get(), size}, *this);
#else
connection->Read(fh, offset, size, *this); connection->Read(fh, offset, size, *this);
#endif
state = State::READ; state = State::READ;
} }
@ -200,7 +214,16 @@ NfsFileReader::StatCallback(const struct nfs_stat_64 *st) noexcept
inline void inline void
NfsFileReader::ReadCallback(std::size_t nbytes, const void *data) noexcept NfsFileReader::ReadCallback(std::size_t nbytes, const void *data) noexcept
{ {
#ifdef LIBNFS_API_2
(void)data;
assert(read_buffer);
const auto buffer = std::move(read_buffer);
OnNfsFileRead({buffer.get(), nbytes});
#else
OnNfsFileRead({static_cast<const std::byte *>(data), nbytes}); OnNfsFileRead({static_cast<const std::byte *>(data), nbytes});
#endif
} }
void void

View File

@ -14,6 +14,10 @@
#include <span> #include <span>
#include <string> #include <string>
#ifdef LIBNFS_API_2
#include <memory>
#endif
struct nfsfh; struct nfsfh;
struct nfs_stat_64; struct nfs_stat_64;
class NfsConnection; class NfsConnection;
@ -51,6 +55,10 @@ class NfsFileReader : NfsLease, NfsCallback {
*/ */
InjectEvent defer_open; InjectEvent defer_open;
#ifdef LIBNFS_API_2
std::unique_ptr<std::byte[]> read_buffer;
#endif
public: public:
NfsFileReader() noexcept; NfsFileReader() noexcept;
~NfsFileReader() noexcept; ~NfsFileReader() noexcept;

View File

@ -4,6 +4,13 @@ if not nfs_dep.found()
subdir_done() subdir_done()
endif endif
if nfs_dep.version().version_compare('>=6')
# libnfs has no version macro therefore we must detect the API
# version 2 at configure time
nfs_dep = declare_dependency(compile_args: '-DLIBNFS_API_2',
dependencies: nfs_dep)
endif
nfs = static_library( nfs = static_library(
'nfs', 'nfs',
'Connection.cxx', 'Connection.cxx',