diff options
Diffstat (limited to 'src/tools/rbd_wnbd/wnbd_handler.h')
-rw-r--r-- | src/tools/rbd_wnbd/wnbd_handler.h | 186 |
1 files changed, 186 insertions, 0 deletions
diff --git a/src/tools/rbd_wnbd/wnbd_handler.h b/src/tools/rbd_wnbd/wnbd_handler.h new file mode 100644 index 000000000..9a8217745 --- /dev/null +++ b/src/tools/rbd_wnbd/wnbd_handler.h @@ -0,0 +1,186 @@ +/* + * Ceph - scalable distributed file system + * + * Copyright (C) 2020 SUSE LINUX GmbH + * + * This is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software + * Foundation. See file COPYING. + * + */ + +#ifndef WNBD_HANDLER_H +#define WNBD_HANDLER_H + +#include <wnbd.h> + +#include "common/admin_socket.h" +#include "common/ceph_context.h" +#include "common/Thread.h" + +#include "include/rbd/librbd.hpp" +#include "include/xlist.h" + +#include "global/global_context.h" + +// TODO: make this configurable. +#define RBD_WNBD_MAX_TRANSFER 2 * 1024 * 1024 +#define SOFT_REMOVE_RETRY_INTERVAL 2 +#define DEFAULT_SOFT_REMOVE_TIMEOUT 15 +#define DEFAULT_IO_WORKER_COUNT 4 + +// Not defined by mingw. +#ifndef SCSI_ADSENSE_UNRECOVERED_ERROR +#define SCSI_ADSENSE_UNRECOVERED_ERROR 0x11 +#endif + +// The following will be assigned to the "Owner" field of the WNBD +// parameters, which can be used to determine the application managing +// a disk. We'll ignore other disks. +#define RBD_WNBD_OWNER_NAME "ceph-rbd-wnbd" + +class WnbdHandler; + +class WnbdAdminHook : public AdminSocketHook { + WnbdHandler *m_handler; + +public: + explicit WnbdAdminHook(WnbdHandler *handler) : + m_handler(handler) { + g_ceph_context->get_admin_socket()->register_command( + "wnbd stats", this, "get WNBD stats"); + } + ~WnbdAdminHook() override { + g_ceph_context->get_admin_socket()->unregister_commands(this); + } + + int call(std::string_view command, const cmdmap_t& cmdmap, + Formatter *f, std::ostream& errss, bufferlist& out) override; +}; + + +class WnbdHandler +{ +private: + librbd::Image ℑ + std::string instance_name; + uint64_t block_count; + uint32_t block_size; + bool readonly; + bool rbd_cache_enabled; + uint32_t io_req_workers; + uint32_t io_reply_workers; + WnbdAdminHook* admin_hook; + boost::asio::thread_pool* reply_tpool; + +public: + WnbdHandler(librbd::Image& _image, std::string _instance_name, + uint64_t _block_count, uint32_t _block_size, + bool _readonly, bool _rbd_cache_enabled, + uint32_t _io_req_workers, + uint32_t _io_reply_workers) + : image(_image) + , instance_name(_instance_name) + , block_count(_block_count) + , block_size(_block_size) + , readonly(_readonly) + , rbd_cache_enabled(_rbd_cache_enabled) + , io_req_workers(_io_req_workers) + , io_reply_workers(_io_reply_workers) + { + admin_hook = new WnbdAdminHook(this); + // Instead of relying on librbd's own thread pool, we're going to use a + // separate one. This allows us to make assumptions on the threads that + // are going to send the IO replies and thus be able to cache Windows + // OVERLAPPED structures. + reply_tpool = new boost::asio::thread_pool(_io_reply_workers); + } + + int start(); + // Wait for the handler to stop, which normally happens when the driver + // passes the "Disconnect" request. + int wait(); + void shutdown(); + + int dump_stats(Formatter *f); + + ~WnbdHandler(); + + static VOID LogMessage( + WnbdLogLevel LogLevel, + const char* Message, + const char* FileName, + UINT32 Line, + const char* FunctionName); + +private: + ceph::mutex shutdown_lock = ceph::make_mutex("WnbdHandler::DisconnectLocker"); + bool started = false; + bool terminated = false; + WNBD_DISK* wnbd_disk = nullptr; + + struct IOContext + { + xlist<IOContext*>::item item; + WnbdHandler *handler = nullptr; + WNBD_STATUS wnbd_status = {0}; + WnbdRequestType req_type = WnbdReqTypeUnknown; + uint64_t req_handle = 0; + uint32_t err_code = 0; + size_t req_size; + uint64_t req_from; + bufferlist data; + + IOContext() + : item(this) + {} + + void set_sense(uint8_t sense_key, uint8_t asc, uint64_t info); + void set_sense(uint8_t sense_key, uint8_t asc); + }; + + friend std::ostream &operator<<(std::ostream &os, const IOContext &ctx); + + void send_io_response(IOContext *ctx); + + static void aio_callback(librbd::completion_t cb, void *arg); + + // WNBD IO entry points + static void Read( + PWNBD_DISK Disk, + UINT64 RequestHandle, + PVOID Buffer, + UINT64 BlockAddress, + UINT32 BlockCount, + BOOLEAN ForceUnitAccess); + static void Write( + PWNBD_DISK Disk, + UINT64 RequestHandle, + PVOID Buffer, + UINT64 BlockAddress, + UINT32 BlockCount, + BOOLEAN ForceUnitAccess); + static void Flush( + PWNBD_DISK Disk, + UINT64 RequestHandle, + UINT64 BlockAddress, + UINT32 BlockCount); + static void Unmap( + PWNBD_DISK Disk, + UINT64 RequestHandle, + PWNBD_UNMAP_DESCRIPTOR Descriptors, + UINT32 Count); + + static constexpr WNBD_INTERFACE RbdWnbdInterface = + { + Read, + Write, + Flush, + Unmap, + }; +}; + +std::ostream &operator<<(std::ostream &os, const WnbdHandler::IOContext &ctx); + +#endif // WNBD_HANDLER_H |