From 31e583e9f8d14b9e67eab2581be8e21cd5712b47 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Mon, 13 May 2024 18:11:24 +0200 Subject: [PATCH] lib/nfs: initial support for libnfs API 2 Commit https://github.com/sahlberg/libnfs/commit/5e8f7ce273308eb77f94248f4501e574a703c1a5 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 --- NEWS | 1 + src/lib/nfs/Connection.cxx | 33 +++++++++++++++++++++++++++++---- src/lib/nfs/Connection.hxx | 15 +++++++++++++-- src/lib/nfs/FileReader.cxx | 25 ++++++++++++++++++++++++- src/lib/nfs/FileReader.hxx | 8 ++++++++ src/lib/nfs/meson.build | 7 +++++++ 6 files changed, 82 insertions(+), 7 deletions(-) diff --git a/NEWS b/NEWS index bc5a20cbd..c4a566aa8 100644 --- a/NEWS +++ b/NEWS @@ -26,6 +26,7 @@ ver 0.24 (not yet released) * storage - curl: optimize database update - nfs: require libnfs 4.0 or later + - nfs: support libnfs 6 (API version 2) - nfs: support libnfs URL arguments * input - alsa: limit ALSA buffer time to 2 seconds diff --git a/src/lib/nfs/Connection.cxx b/src/lib/nfs/Connection.cxx index 3c5ca5d09..ee888698a 100644 --- a/src/lib/nfs/Connection.cxx +++ b/src/lib/nfs/Connection.cxx @@ -81,11 +81,25 @@ NfsConnection::CancellableCallback::Stat(nfs_context *ctx, inline void NfsConnection::CancellableCallback::Read(nfs_context *ctx, struct nfsfh *fh, - uint64_t offset, size_t size) + uint64_t offset, +#ifdef LIBNFS_API_2 + std::span dest +#else + std::size_t size +#endif + ) { 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) throw NfsClientError(ctx, "nfs_pread_async() failed"); } @@ -328,7 +342,12 @@ NfsConnection::Stat(struct nfsfh *fh, NfsCallback &callback) } 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 dest, +#else + std::size_t size, +#endif NfsCallback &callback) { 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); try { - c.Read(context, fh, offset, size); + c.Read(context, fh, offset, +#ifdef LIBNFS_API_2 + dest +#else + size +#endif + ); } catch (...) { callbacks.Remove(c); throw; diff --git a/src/lib/nfs/Connection.hxx b/src/lib/nfs/Connection.hxx index 3c2dbfbb3..c6afb3118 100644 --- a/src/lib/nfs/Connection.hxx +++ b/src/lib/nfs/Connection.hxx @@ -62,7 +62,13 @@ class NfsConnection { void Open(nfs_context *context, const char *path, int flags); void Stat(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 dest +#else + std::size_t size +#endif + ); /** * Cancel the operation and schedule a call to @@ -210,7 +216,12 @@ public: /** * 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 dest, +#else + std::size_t size, +#endif NfsCallback &callback); /** diff --git a/src/lib/nfs/FileReader.cxx b/src/lib/nfs/FileReader.cxx index 84a756a3b..5982e1b3d 100644 --- a/src/lib/nfs/FileReader.cxx +++ b/src/lib/nfs/FileReader.cxx @@ -59,7 +59,13 @@ NfsFileReader::CancelOrClose() noexcept else if (state > State::OPEN) /* one async operation in progress: cancel it and 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) /* we don't have a file handle yet - just cancel the async operation */ @@ -116,7 +122,15 @@ NfsFileReader::Read(uint64_t offset, size_t size) { assert(state == State::IDLE); +#ifdef LIBNFS_API_2 + assert(!read_buffer); + // TOOD read into caller-provided buffer + read_buffer = std::make_unique(size); + connection->Read(fh, offset, {read_buffer.get(), size}, *this); +#else connection->Read(fh, offset, size, *this); +#endif + state = State::READ; } @@ -200,7 +214,16 @@ NfsFileReader::StatCallback(const struct nfs_stat_64 *st) noexcept inline void 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(data), nbytes}); +#endif } void diff --git a/src/lib/nfs/FileReader.hxx b/src/lib/nfs/FileReader.hxx index 10caa4f03..3882c2620 100644 --- a/src/lib/nfs/FileReader.hxx +++ b/src/lib/nfs/FileReader.hxx @@ -14,6 +14,10 @@ #include #include +#ifdef LIBNFS_API_2 +#include +#endif + struct nfsfh; struct nfs_stat_64; class NfsConnection; @@ -51,6 +55,10 @@ class NfsFileReader : NfsLease, NfsCallback { */ InjectEvent defer_open; +#ifdef LIBNFS_API_2 + std::unique_ptr read_buffer; +#endif + public: NfsFileReader() noexcept; ~NfsFileReader() noexcept; diff --git a/src/lib/nfs/meson.build b/src/lib/nfs/meson.build index ec2263e1b..20a5c9492 100644 --- a/src/lib/nfs/meson.build +++ b/src/lib/nfs/meson.build @@ -4,6 +4,13 @@ if not nfs_dep.found() subdir_done() 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', 'Connection.cxx',