1 /* SPDX-License-Identifier: Apache-2.0 */ 2 /* Copyright (C) 2018 IBM Corp. */ 3 #pragma once 4 5 extern "C" { 6 #include "backend.h" 7 #include "vpnor/backend.h" 8 }; 9 10 #include "vpnor/table.hpp" 11 12 #include <fcntl.h> 13 #include <unistd.h> 14 15 #include <experimental/filesystem> 16 #include <string> 17 18 namespace openpower 19 { 20 namespace virtual_pnor 21 { 22 23 namespace fs = std::experimental::filesystem; 24 25 class Request 26 { 27 public: 28 /** @brief Construct a flash access request 29 * 30 * @param[in] backend - The backend context used to process the request 31 * @param[in] offset - The absolute offset into the flash device as 32 * provided by the mbox message associated with the 33 * request 34 * 35 * The class does not take ownership of the ctx pointer. The lifetime of 36 * the ctx pointer must strictly exceed the lifetime of the class 37 * instance. 38 */ 39 Request(struct backend* backend, size_t offset) : 40 backend(backend), partition(((struct vpnor_data*)backend->priv) 41 ->vpnor->table->partition(offset)), 42 base(partition.data.base << backend->block_size_shift), 43 offset(offset - base) 44 { 45 } 46 Request(const Request&) = delete; 47 Request& operator=(const Request&) = delete; 48 Request(Request&&) = default; 49 Request& operator=(Request&&) = default; 50 ~Request() = default; 51 52 ssize_t read(void* dst, size_t len) 53 { 54 len = clamp(len); 55 constexpr auto flags = O_RDONLY; 56 fs::path path = getPartitionFilePath(flags); 57 return fulfil(path, flags, dst, len); 58 } 59 60 ssize_t write(void* dst, size_t len) 61 { 62 if (len != clamp(len)) 63 { 64 std::stringstream err; 65 err << "Request size 0x" << std::hex << len << " from offset 0x" 66 << std::hex << offset << " exceeds the partition size 0x" 67 << std::hex 68 << (partition.data.size << backend->block_size_shift); 69 throw OutOfBoundsOffset(err.str()); 70 } 71 constexpr auto flags = O_RDWR; 72 /* Ensure file is at least the size of the maximum access */ 73 fs::path path = getPartitionFilePath(flags); 74 resize(path, len); 75 return fulfil(path, flags, dst, len); 76 } 77 78 private: 79 /** @brief Clamp the access length to the maximum supported by the ToC */ 80 size_t clamp(size_t len); 81 82 /** @brief Ensure the backing file is sized appropriately for the access 83 * 84 * We need to ensure the file is big enough to satisfy the request so that 85 * mmap() will succeed for the required size. 86 * 87 * @return The valid access length 88 * 89 * Throws: std::system_error 90 */ 91 void resize(const std::experimental::filesystem::path& path, size_t len); 92 93 /** @brief Returns the partition file path associated with the offset. 94 * 95 * The search strategy for the partition file depends on the value of the 96 * flags parameter. 97 * 98 * For the O_RDONLY case: 99 * 100 * 1. Depending on the partition type,tries to open the file 101 * from the associated partition(RW/PRSV/RO). 102 * 1a. if file not found in the corresponding 103 * partition(RW/PRSV/RO) then tries to read the file from 104 * the read only partition. 105 * 1b. if the file not found in the read only partition then 106 * throw exception. 107 * 108 * For the O_RDWR case: 109 * 110 * 1. Depending on the partition type tries to open the file 111 * from the associated partition. 112 * 1a. if file not found in the corresponding partition(RW/PRSV) 113 * then copy the file from the read only partition to the (RW/PRSV) 114 * partition depending on the partition type. 115 * 1b. if the file not found in the read only partition then throw 116 * exception. 117 * 118 * @param[in] flags - The flags that will be used to open the file. Must 119 * be one of O_RDONLY or O_RDWR. 120 * 121 * Post-condition: The file described by the returned path exists 122 * 123 * Throws: std::filesystem_error, std::bad_alloc 124 */ 125 std::experimental::filesystem::path getPartitionFilePath(int flags); 126 127 /** @brief Fill dst with the content of the partition relative to offset. 128 * 129 * @param[in] offset - The pnor offset(bytes). 130 * @param[out] dst - The buffer to fill with partition data 131 * @param[in] len - The length of the destination buffer 132 */ 133 size_t fulfil(const std::experimental::filesystem::path& path, int flags, 134 void* dst, size_t len); 135 136 struct backend* backend; 137 const pnor_partition& partition; 138 size_t base; 139 size_t offset; 140 }; 141 142 } // namespace virtual_pnor 143 } // namespace openpower 144